Home Explore Blog CI



nixpkgs

nixos/doc/manual/development/freeform-modules.section.md
a88f2004fab895c1a2a5b2e6c9fc367ddb2ad27dc242a75000000003000008f3
# Freeform modules {#sec-freeform-modules}

Freeform modules allow you to define values for option paths that have
not been declared explicitly. This can be used to add attribute-specific
types to what would otherwise have to be `attrsOf` options in order to
accept all attribute names.

This feature can be enabled by using the attribute `freeformType` to
define a freeform type. By doing this, all assignments without an
associated option will be merged using the freeform type and combined
into the resulting `config` set. Since this feature nullifies name
checking for entire option trees, it is only recommended for use in
submodules.

::: {#ex-freeform-module .example}
### Freeform submodule

The following shows a submodule assigning a freeform type that allows
arbitrary attributes with `str` values below `settings`, but also
declares an option for the `settings.port` attribute to have it
type-checked and assign a default value. See
[Example: Declaring a type-checked `settings` attribute](#ex-settings-typed-attrs)
for a more complete example.

```nix
{ lib, config, ... }: {

  options.settings = lib.mkOption {
    type = lib.types.submodule {

      freeformType = with lib.types; attrsOf str;

      # We want this attribute to be checked for the correct type
      options.port = lib.mkOption {
        type = lib.types.port;
        # Declaring the option also allows defining a default value
        default = 8080;
      };

    };
  };
}
```

And the following shows what such a module then allows

```nix
{
  # Not a declared option, but the freeform type allows this
  settings.logLevel = "debug";

  # Not allowed because the the freeform type only allows strings
  # settings.enable = true;

  # Allowed because there is a port option declared
  settings.port = 80;

  # Not allowed because the port option doesn't allow strings
  # settings.port = "443";
}
```
:::

::: {.note}
Freeform attributes cannot depend on other attributes of the same set
without infinite recursion:

```nix
{
  # This throws infinite recursion encountered
  settings.logLevel = lib.mkIf (config.settings.port == 80) "debug";
}
```

To prevent this, declare options for all attributes that need to depend
on others. For above example this means to declare `logLevel` to be an
option.
:::

Chunks
ad7f3e40 (1st chunk of `nixos/doc/manual/development/freeform-modules.section.md`)
Title: Freeform Modules
Summary
Freeform modules allow defining values for undeclared option paths by specifying a `freeformType`. This merges assignments using the specified type into the resulting `config` set, but bypasses name checking. It's recommended for use in submodules only. The example demonstrates a submodule with a freeform type that accepts arbitrary attributes with `str` values under `settings`, while still type-checking and providing a default value for the `settings.port` attribute. Freeform attributes can't depend on other attributes in the same set without causing infinite recursion; declare options for attributes that need to depend on others to avoid this.