1# Freeform modules {#sec-freeform-modules}
2
3Freeform modules allow you to define values for option paths that have
4not been declared explicitly. This can be used to add attribute-specific
5types to what would otherwise have to be `attrsOf` options in order to
6accept all attribute names.
7
8This feature can be enabled by using the attribute `freeformType` to
9define a freeform type. By doing this, all assignments without an
10associated option will be merged using the freeform type and combined
11into the resulting `config` set. Since this feature nullifies name
12checking for entire option trees, it is only recommended for use in
13submodules.
14
15::: {#ex-freeform-module .example}
16::: {.title}
17**Example: Freeform submodule**
18:::
19The following shows a submodule assigning a freeform type that allows
20arbitrary attributes with `str` values below `settings`, but also
21declares an option for the `settings.port` attribute to have it
22type-checked and assign a default value. See
23[Example: Declaring a type-checked `settings` attribute](#ex-settings-typed-attrs)
24for a more complete example.
25
26```nix
27{ lib, config, ... }: {
28
29 options.settings = lib.mkOption {
30 type = lib.types.submodule {
31
32 freeformType = with lib.types; attrsOf str;
33
34 # We want this attribute to be checked for the correct type
35 options.port = lib.mkOption {
36 type = lib.types.port;
37 # Declaring the option also allows defining a default value
38 default = 8080;
39 };
40
41 };
42 };
43}
44```
45
46And the following shows what such a module then allows
47
48```nix
49{
50 # Not a declared option, but the freeform type allows this
51 settings.logLevel = "debug";
52
53 # Not allowed because the the freeform type only allows strings
54 # settings.enable = true;
55
56 # Allowed because there is a port option declared
57 settings.port = 80;
58
59 # Not allowed because the port option doesn't allow strings
60 # settings.port = "443";
61}
62```
63:::
64
65::: {.note}
66Freeform attributes cannot depend on other attributes of the same set
67without infinite recursion:
68
69```nix
70{
71 # This throws infinite recursion encountered
72 settings.logLevel = lib.mkIf (config.settings.port == 80) "debug";
73}
74```
75
76To prevent this, declare options for all attributes that need to depend
77on others. For above example this means to declare `logLevel` to be an
78option.
79:::