Merge pull request #129136 from bobby285271/pr14

nixos/doc: convert "Chapter 58. Writing NixOS Modules" to CommonMark
This commit is contained in:
Jörg Thalheim 2021-09-07 06:28:57 +01:00 committed by GitHub
commit c7d32059b1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
25 changed files with 3052 additions and 1712 deletions

View file

@ -0,0 +1,79 @@
# 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}
::: {.title}
**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.
:::

View file

@ -1,68 +0,0 @@
<section xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xi="http://www.w3.org/2001/XInclude"
version="5.0"
xml:id="sec-freeform-modules">
<title>Freeform modules</title>
<para>
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 <literal>attrsOf</literal> options in order to accept all attribute names.
</para>
<para>
This feature can be enabled by using the attribute <literal>freeformType</literal> 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 <literal>config</literal> set. Since this feature nullifies name checking for entire option trees, it is only recommended for use in submodules.
</para>
<example xml:id="ex-freeform-module">
<title>Freeform submodule</title>
<para>
The following shows a submodule assigning a freeform type that allows arbitrary attributes with <literal>str</literal> values below <literal>settings</literal>, but also declares an option for the <literal>settings.port</literal> attribute to have it type-checked and assign a default value. See <xref linkend="ex-settings-typed-attrs"/> for a more complete example.
</para>
<programlisting>
{ 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;
};
};
};
}
</programlisting>
<para>
And the following shows what such a module then allows
</para>
<programlisting>
{
# 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";
}
</programlisting>
</example>
<note>
<para>
Freeform attributes cannot depend on other attributes of the same set without infinite recursion:
<programlisting>
{
# This throws infinite recursion encountered
settings.logLevel = lib.mkIf (config.settings.port == 80) "debug";
}
</programlisting>
To prevent this, declare options for all attributes that need to depend on others. For above example this means to declare <literal>logLevel</literal> to be an option.
</para>
</note>
</section>

View file

@ -0,0 +1,46 @@
# Importing Modules {#sec-importing-modules}
Sometimes NixOS modules need to be used in configuration but exist
outside of Nixpkgs. These modules can be imported:
```nix
{ config, lib, pkgs, ... }:
{
imports =
[ # Use a locally-available module definition in
# ./example-module/default.nix
./example-module
];
services.exampleModule.enable = true;
}
```
The environment variable `NIXOS_EXTRA_MODULE_PATH` is an absolute path
to a NixOS module that is included alongside the Nixpkgs NixOS modules.
Like any NixOS module, this module can import additional modules:
```nix
# ./module-list/default.nix
[
./example-module1
./example-module2
]
```
```nix
# ./extra-module/default.nix
{ imports = import ./module-list.nix; }
```
```nix
# NIXOS_EXTRA_MODULE_PATH=/absolute/path/to/extra-module
{ config, lib, pkgs, ... }:
{
# No `imports` needed
services.exampleModule1.enable = true;
}
```

View file

@ -1,56 +0,0 @@
<section xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xi="http://www.w3.org/2001/XInclude"
version="5.0"
xml:id="sec-importing-modules">
<title>Importing Modules</title>
<para>
Sometimes NixOS modules need to be used in configuration but exist outside of
Nixpkgs. These modules can be imported:
</para>
<programlisting>
{ config, lib, pkgs, ... }:
{
imports =
[ # Use a locally-available module definition in
# ./example-module/default.nix
./example-module
];
services.exampleModule.enable = true;
}
</programlisting>
<para>
The environment variable <literal>NIXOS_EXTRA_MODULE_PATH</literal> is an
absolute path to a NixOS module that is included alongside the Nixpkgs NixOS
modules. Like any NixOS module, this module can import additional modules:
</para>
<programlisting>
# ./module-list/default.nix
[
./example-module1
./example-module2
]
</programlisting>
<programlisting>
# ./extra-module/default.nix
{ imports = import ./module-list.nix; }
</programlisting>
<programlisting>
# NIXOS_EXTRA_MODULE_PATH=/absolute/path/to/extra-module
{ config, lib, pkgs, ... }:
{
# No `imports` needed
services.exampleModule1.enable = true;
}
</programlisting>
</section>

View file

@ -0,0 +1,40 @@
# Meta Attributes {#sec-meta-attributes}
Like Nix packages, NixOS modules can declare meta-attributes to provide
extra information. Module meta attributes are defined in the `meta.nix`
special module.
`meta` is a top level attribute like `options` and `config`. Available
meta-attributes are `maintainers` and `doc`.
Each of the meta-attributes must be defined at most once per module
file.
```nix
{ config, lib, pkgs, ... }:
{
options = {
...
};
config = {
...
};
meta = {
maintainers = with lib.maintainers; [ ericsagnes ];
doc = ./default.xml;
};
}
```
- `maintainers` contains a list of the module maintainers.
- `doc` points to a valid DocBook file containing the module
documentation. Its contents is automatically added to
[](#ch-configuration). Changes to a module documentation have to
be checked to not break building the NixOS manual:
```ShellSession
$ nix-build nixos/release.nix -A manual.x86_64-linux
```

View file

@ -1,63 +0,0 @@
<section xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xi="http://www.w3.org/2001/XInclude"
version="5.0"
xml:id="sec-meta-attributes">
<title>Meta Attributes</title>
<para>
Like Nix packages, NixOS modules can declare meta-attributes to provide extra
information. Module meta attributes are defined in the
<filename
xlink:href="https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/misc/meta.nix">meta.nix</filename>
special module.
</para>
<para>
<literal>meta</literal> is a top level attribute like
<literal>options</literal> and <literal>config</literal>. Available
meta-attributes are <literal>maintainers</literal> and
<literal>doc</literal>.
</para>
<para>
Each of the meta-attributes must be defined at most once per module file.
</para>
<programlisting>
{ config, lib, pkgs, ... }:
{
options = {
...
};
config = {
...
};
meta = {
maintainers = with lib.maintainers; [ ericsagnes ]; <co
xml:id='modules-meta-1' />
doc = ./default.xml; <co xml:id='modules-meta-2' />
};
}
</programlisting>
<calloutlist>
<callout arearefs='modules-meta-1'>
<para>
<varname>maintainers</varname> contains a list of the module maintainers.
</para>
</callout>
<callout arearefs='modules-meta-2'>
<para>
<varname>doc</varname> points to a valid DocBook file containing the module
documentation. Its contents is automatically added to
<xref
linkend="ch-configuration"/>. Changes to a module documentation
have to be checked to not break building the NixOS manual:
</para>
<screen><prompt>$ </prompt>nix-build nixos/release.nix -A manual.x86_64-linux</screen>
</callout>
</calloutlist>
</section>

View file

@ -0,0 +1,136 @@
# Option Declarations {#sec-option-declarations}
An option declaration specifies the name, type and description of a
NixOS configuration option. It is invalid to define an option that
hasn't been declared in any module. An option declaration generally
looks like this:
```nix
options = {
name = mkOption {
type = type specification;
default = default value;
example = example value;
description = "Description for use in the NixOS manual.";
};
};
```
The attribute names within the `name` attribute path must be camel
cased in general but should, as an exception, match the [ package
attribute name](https://nixos.org/nixpkgs/manual/#sec-package-naming)
when referencing a Nixpkgs package. For example, the option
`services.nix-serve.bindAddress` references the `nix-serve` Nixpkgs
package.
The function `mkOption` accepts the following arguments.
`type`
: The type of the option (see [](#sec-option-types)). It may be
omitted, but that's not advisable since it may lead to errors that
are hard to diagnose.
`default`
: The default value used if no value is defined by any module. A
default is not required; but if a default is not given, then users
of the module will have to define the value of the option, otherwise
an error will be thrown.
`example`
: An example value that will be shown in the NixOS manual.
`description`
: A textual description of the option, in DocBook format, that will be
included in the NixOS manual.
## Extensible Option Types {#sec-option-declarations-eot}
Extensible option types is a feature that allow to extend certain types
declaration through multiple module files. This feature only work with a
restricted set of types, namely `enum` and `submodules` and any composed
forms of them.
Extensible option types can be used for `enum` options that affects
multiple modules, or as an alternative to related `enable` options.
As an example, we will take the case of display managers. There is a
central display manager module for generic display manager options and a
module file per display manager backend (sddm, gdm \...).
There are two approach to this module structure:
- Managing the display managers independently by adding an enable
option to every display manager module backend. (NixOS)
- Managing the display managers in the central module by adding an
option to select which display manager backend to use.
Both approaches have problems.
Making backends independent can quickly become hard to manage. For
display managers, there can be only one enabled at a time, but the type
system can not enforce this restriction as there is no relation between
each backend `enable` option. As a result, this restriction has to be
done explicitely by adding assertions in each display manager backend
module.
On the other hand, managing the display managers backends in the central
module will require to change the central module option every time a new
backend is added or removed.
By using extensible option types, it is possible to create a placeholder
option in the central module
([Example: Extensible type placeholder in the service module](#ex-option-declaration-eot-service)),
and to extend it in each backend module
([Example: Extending `services.xserver.displayManager.enable` in the `gdm` module](#ex-option-declaration-eot-backend-gdm),
[Example: Extending `services.xserver.displayManager.enable` in the `sddm` module](#ex-option-declaration-eot-backend-sddm)).
As a result, `displayManager.enable` option values can be added without
changing the main service module file and the type system automatically
enforce that there can only be a single display manager enabled.
::: {#ex-option-declaration-eot-service .example}
::: {.title}
**Example: Extensible type placeholder in the service module**
:::
```nix
services.xserver.displayManager.enable = mkOption {
description = "Display manager to use";
type = with types; nullOr (enum [ ]);
};
```
:::
::: {#ex-option-declaration-eot-backend-gdm .example}
::: {.title}
**Example: Extending `services.xserver.displayManager.enable` in the `gdm` module**
:::
```nix
services.xserver.displayManager.enable = mkOption {
type = with types; nullOr (enum [ "gdm" ]);
};
```
:::
::: {#ex-option-declaration-eot-backend-sddm .example}
::: {.title}
**Example: Extending `services.xserver.displayManager.enable` in the `sddm` module**
:::
```nix
services.xserver.displayManager.enable = mkOption {
type = with types; nullOr (enum [ "sddm" ]);
};
```
:::
The placeholder declaration is a standard `mkOption` declaration, but it
is important that extensible option declarations only use the `type`
argument.
Extensible option types work with any of the composed variants of `enum`
such as `with types; nullOr (enum [ "foo" "bar" ])` or `with types;
listOf (enum [ "foo" "bar" ])`.

View file

@ -1,199 +0,0 @@
<section xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xi="http://www.w3.org/2001/XInclude"
version="5.0"
xml:id="sec-option-declarations">
<title>Option Declarations</title>
<para>
An option declaration specifies the name, type and description of a NixOS
configuration option. It is invalid to define an option that hasnt been
declared in any module. An option declaration generally looks like this:
<programlisting>
options = {
<replaceable>name</replaceable> = mkOption {
type = <replaceable>type specification</replaceable>;
default = <replaceable>default value</replaceable>;
example = <replaceable>example value</replaceable>;
description = "<replaceable>Description for use in the NixOS manual.</replaceable>";
};
};
</programlisting>
The attribute names within the <replaceable>name</replaceable> attribute path
must be camel cased in general but should, as an exception, match the
<link
xlink:href="https://nixos.org/nixpkgs/manual/#sec-package-naming">
package attribute name</link> when referencing a Nixpkgs package. For
example, the option <varname>services.nix-serve.bindAddress</varname>
references the <varname>nix-serve</varname> Nixpkgs package.
</para>
<para>
The function <varname>mkOption</varname> accepts the following arguments.
<variablelist>
<varlistentry>
<term>
<varname>type</varname>
</term>
<listitem>
<para>
The type of the option (see <xref linkend='sec-option-types' />). It may
be omitted, but thats not advisable since it may lead to errors that
are hard to diagnose.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<varname>default</varname>
</term>
<listitem>
<para>
The default value used if no value is defined by any module. A default is
not required; but if a default is not given, then users of the module
will have to define the value of the option, otherwise an error will be
thrown.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<varname>example</varname>
</term>
<listitem>
<para>
An example value that will be shown in the NixOS manual.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<varname>description</varname>
</term>
<listitem>
<para>
A textual description of the option, in DocBook format, that will be
included in the NixOS manual.
</para>
</listitem>
</varlistentry>
</variablelist>
</para>
<section xml:id="sec-option-declarations-eot">
<title>Extensible Option Types</title>
<para>
Extensible option types is a feature that allow to extend certain types
declaration through multiple module files. This feature only work with a
restricted set of types, namely <literal>enum</literal> and
<literal>submodules</literal> and any composed forms of them.
</para>
<para>
Extensible option types can be used for <literal>enum</literal> options that
affects multiple modules, or as an alternative to related
<literal>enable</literal> options.
</para>
<para>
As an example, we will take the case of display managers. There is a central
display manager module for generic display manager options and a module file
per display manager backend (sddm, gdm ...).
</para>
<para>
There are two approach to this module structure:
<itemizedlist>
<listitem>
<para>
Managing the display managers independently by adding an enable option to
every display manager module backend. (NixOS)
</para>
</listitem>
<listitem>
<para>
Managing the display managers in the central module by adding an option
to select which display manager backend to use.
</para>
</listitem>
</itemizedlist>
</para>
<para>
Both approaches have problems.
</para>
<para>
Making backends independent can quickly become hard to manage. For display
managers, there can be only one enabled at a time, but the type system can
not enforce this restriction as there is no relation between each backend
<literal>enable</literal> option. As a result, this restriction has to be
done explicitely by adding assertions in each display manager backend
module.
</para>
<para>
On the other hand, managing the display managers backends in the central
module will require to change the central module option every time a new
backend is added or removed.
</para>
<para>
By using extensible option types, it is possible to create a placeholder
option in the central module
(<xref linkend='ex-option-declaration-eot-service'
/>), and to extend
it in each backend module
(<xref
linkend='ex-option-declaration-eot-backend-gdm' />,
<xref
linkend='ex-option-declaration-eot-backend-sddm' />).
</para>
<para>
As a result, <literal>displayManager.enable</literal> option values can be
added without changing the main service module file and the type system
automatically enforce that there can only be a single display manager
enabled.
</para>
<example xml:id='ex-option-declaration-eot-service'>
<title>Extensible type placeholder in the service module</title>
<screen>
services.xserver.displayManager.enable = mkOption {
description = "Display manager to use";
type = with types; nullOr (enum [ ]);
};</screen>
</example>
<example xml:id='ex-option-declaration-eot-backend-gdm'>
<title>Extending <literal>services.xserver.displayManager.enable</literal> in the <literal>gdm</literal> module</title>
<screen>
services.xserver.displayManager.enable = mkOption {
type = with types; nullOr (enum [ "gdm" ]);
};</screen>
</example>
<example xml:id='ex-option-declaration-eot-backend-sddm'>
<title>Extending <literal>services.xserver.displayManager.enable</literal> in the <literal>sddm</literal> module</title>
<screen>
services.xserver.displayManager.enable = mkOption {
type = with types; nullOr (enum [ "sddm" ]);
};</screen>
</example>
<para>
The placeholder declaration is a standard <literal>mkOption</literal>
declaration, but it is important that extensible option declarations only
use the <literal>type</literal> argument.
</para>
<para>
Extensible option types work with any of the composed variants of
<literal>enum</literal> such as <literal>with types; nullOr (enum [ "foo"
"bar" ])</literal> or <literal>with types; listOf (enum [ "foo" "bar"
])</literal>.
</para>
</section>
</section>

View file

@ -0,0 +1,91 @@
# Option Definitions {#sec-option-definitions}
Option definitions are generally straight-forward bindings of values to
option names, like
```nix
config = {
services.httpd.enable = true;
};
```
However, sometimes you need to wrap an option definition or set of
option definitions in a *property* to achieve certain effects:
## Delaying Conditionals {#sec-option-definitions-delaying-conditionals .unnumbered}
If a set of option definitions is conditional on the value of another
option, you may need to use `mkIf`. Consider, for instance:
```nix
config = if config.services.httpd.enable then {
environment.systemPackages = [ ... ];
...
} else {};
```
This definition will cause Nix to fail with an "infinite recursion"
error. Why? Because the value of `config.services.httpd.enable` depends
on the value being constructed here. After all, you could also write the
clearly circular and contradictory:
```nix
config = if config.services.httpd.enable then {
services.httpd.enable = false;
} else {
services.httpd.enable = true;
};
```
The solution is to write:
```nix
config = mkIf config.services.httpd.enable {
environment.systemPackages = [ ... ];
...
};
```
The special function `mkIf` causes the evaluation of the conditional to
be "pushed down" into the individual definitions, as if you had written:
```nix
config = {
environment.systemPackages = if config.services.httpd.enable then [ ... ] else [];
...
};
```
## Setting Priorities {#sec-option-definitions-setting-priorities .unnumbered}
A module can override the definitions of an option in other modules by
setting a *priority*. All option definitions that do not have the lowest
priority value are discarded. By default, option definitions have
priority 1000. You can specify an explicit priority by using
`mkOverride`, e.g.
```nix
services.openssh.enable = mkOverride 10 false;
```
This definition causes all other definitions with priorities above 10 to
be discarded. The function `mkForce` is equal to `mkOverride 50`.
## Merging Configurations {#sec-option-definitions-merging .unnumbered}
In conjunction with `mkIf`, it is sometimes useful for a module to
return multiple sets of option definitions, to be merged together as if
they were declared in separate modules. This can be done using
`mkMerge`:
```nix
config = mkMerge
[ # Unconditional stuff.
{ environment.systemPackages = [ ... ];
}
# Conditional stuff.
(mkIf config.services.bla.enable {
environment.systemPackages = [ ... ];
})
];
```

View file

@ -1,99 +0,0 @@
<section xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xi="http://www.w3.org/2001/XInclude"
version="5.0"
xml:id="sec-option-definitions">
<title>Option Definitions</title>
<para>
Option definitions are generally straight-forward bindings of values to
option names, like
<programlisting>
config = {
services.httpd.enable = true;
};
</programlisting>
However, sometimes you need to wrap an option definition or set of option
definitions in a <emphasis>property</emphasis> to achieve certain effects:
</para>
<simplesect xml:id="sec-option-definitions-delaying-conditionals">
<title>Delaying Conditionals</title>
<para>
If a set of option definitions is conditional on the value of another
option, you may need to use <varname>mkIf</varname>. Consider, for instance:
<programlisting>
config = if config.services.httpd.enable then {
environment.systemPackages = [ <replaceable>...</replaceable> ];
<replaceable>...</replaceable>
} else {};
</programlisting>
This definition will cause Nix to fail with an “infinite recursion”
error. Why? Because the value of
<option>config.services.httpd.enable</option> depends on the value being
constructed here. After all, you could also write the clearly circular and
contradictory:
<programlisting>
config = if config.services.httpd.enable then {
services.httpd.enable = false;
} else {
services.httpd.enable = true;
};
</programlisting>
The solution is to write:
<programlisting>
config = mkIf config.services.httpd.enable {
environment.systemPackages = [ <replaceable>...</replaceable> ];
<replaceable>...</replaceable>
};
</programlisting>
The special function <varname>mkIf</varname> causes the evaluation of the
conditional to be “pushed down” into the individual definitions, as if
you had written:
<programlisting>
config = {
environment.systemPackages = if config.services.httpd.enable then [ <replaceable>...</replaceable> ] else [];
<replaceable>...</replaceable>
};
</programlisting>
</para>
</simplesect>
<simplesect xml:id="sec-option-definitions-setting-priorities">
<title>Setting Priorities</title>
<para>
A module can override the definitions of an option in other modules by
setting a <emphasis>priority</emphasis>. All option definitions that do not
have the lowest priority value are discarded. By default, option definitions
have priority 1000. You can specify an explicit priority by using
<varname>mkOverride</varname>, e.g.
<programlisting>
services.openssh.enable = mkOverride 10 false;
</programlisting>
This definition causes all other definitions with priorities above 10 to be
discarded. The function <varname>mkForce</varname> is equal to
<varname>mkOverride 50</varname>.
</para>
</simplesect>
<simplesect xml:id="sec-option-definitions-merging">
<title>Merging Configurations</title>
<para>
In conjunction with <literal>mkIf</literal>, it is sometimes useful for a
module to return multiple sets of option definitions, to be merged together
as if they were declared in separate modules. This can be done using
<varname>mkMerge</varname>:
<programlisting>
config = mkMerge
[ # Unconditional stuff.
{ environment.systemPackages = [ <replaceable>...</replaceable> ];
}
# Conditional stuff.
(mkIf config.services.bla.enable {
environment.systemPackages = [ <replaceable>...</replaceable> ];
})
];
</programlisting>
</para>
</simplesect>
</section>

View file

@ -0,0 +1,558 @@
# Options Types {#sec-option-types}
Option types are a way to put constraints on the values a module option
can take. Types are also responsible of how values are merged in case of
multiple value definitions.
## Basic Types {#sec-option-types-basic}
Basic types are the simplest available types in the module system. Basic
types include multiple string types that mainly differ in how definition
merging is handled.
`types.bool`
: A boolean, its values can be `true` or `false`.
`types.path`
: A filesystem path, defined as anything that when coerced to a string
starts with a slash. Even if derivations can be considered as path,
the more specific `types.package` should be preferred.
`types.package`
: A derivation or a store path.
`types.anything`
: A type that accepts any value and recursively merges attribute sets
together. This type is recommended when the option type is unknown.
::: {#ex-types-anything .example}
::: {.title}
**Example: `types.anything` Example**
:::
Two definitions of this type like
```nix
{
str = lib.mkDefault "foo";
pkg.hello = pkgs.hello;
fun.fun = x: x + 1;
}
```
```nix
{
str = lib.mkIf true "bar";
pkg.gcc = pkgs.gcc;
fun.fun = lib.mkForce (x: x + 2);
}
```
will get merged to
```nix
{
str = "bar";
pkg.gcc = pkgs.gcc;
pkg.hello = pkgs.hello;
fun.fun = x: x + 2;
}
```
:::
`types.attrs`
: A free-form attribute set.
::: {.warning}
This type will be deprecated in the future because it doesn\'t
recurse into attribute sets, silently drops earlier attribute
definitions, and doesn\'t discharge `lib.mkDefault`, `lib.mkIf`
and co. For allowing arbitrary attribute sets, prefer
`types.attrsOf types.anything` instead which doesn\'t have these
problems.
:::
Integer-related types:
`types.int`
: A signed integer.
`types.ints.{s8, s16, s32}`
: Signed integers with a fixed length (8, 16 or 32 bits). They go from
2^n/2 to
2^n/21 respectively (e.g. `128` to
`127` for 8 bits).
`types.ints.unsigned`
: An unsigned integer (that is >= 0).
`types.ints.{u8, u16, u32}`
: Unsigned integers with a fixed length (8, 16 or 32 bits). They go
from 0 to 2^n1 respectively (e.g. `0`
to `255` for 8 bits).
`types.ints.positive`
: A positive integer (that is > 0).
`types.port`
: A port number. This type is an alias to
`types.ints.u16`.
String-related types:
`types.str`
: A string. Multiple definitions cannot be merged.
`types.lines`
: A string. Multiple definitions are concatenated with a new line
`"\n"`.
`types.commas`
: A string. Multiple definitions are concatenated with a comma `","`.
`types.envVar`
: A string. Multiple definitions are concatenated with a collon `":"`.
`types.strMatching`
: A string matching a specific regular expression. Multiple
definitions cannot be merged. The regular expression is processed
using `builtins.match`.
## Value Types {#sec-option-types-value}
Value types are types that take a value parameter.
`types.enum` *`l`*
: One element of the list *`l`*, e.g. `types.enum [ "left" "right" ]`.
Multiple definitions cannot be merged.
`types.separatedString` *`sep`*
: A string with a custom separator *`sep`*, e.g.
`types.separatedString "|"`.
`types.ints.between` *`lowest highest`*
: An integer between *`lowest`* and *`highest`* (both inclusive). Useful
for creating types like `types.port`.
`types.submodule` *`o`*
: A set of sub options *`o`*. *`o`* can be an attribute set, a function
returning an attribute set, or a path to a file containing such a
value. Submodules are used in composed types to create modular
options. This is equivalent to
`types.submoduleWith { modules = toList o; shorthandOnlyDefinesConfig = true; }`.
Submodules are detailed in [Submodule](#section-option-types-submodule).
`types.submoduleWith` { *`modules`*, *`specialArgs`* ? {}, *`shorthandOnlyDefinesConfig`* ? false }
: Like `types.submodule`, but more flexible and with better defaults.
It has parameters
- *`modules`* A list of modules to use by default for this
submodule type. This gets combined with all option definitions
to build the final list of modules that will be included.
::: {.note}
Only options defined with this argument are included in rendered
documentation.
:::
- *`specialArgs`* An attribute set of extra arguments to be passed
to the module functions. The option `_module.args` should be
used instead for most arguments since it allows overriding.
*`specialArgs`* should only be used for arguments that can\'t go
through the module fixed-point, because of infinite recursion or
other problems. An example is overriding the `lib` argument,
because `lib` itself is used to define `_module.args`, which
makes using `_module.args` to define it impossible.
- *`shorthandOnlyDefinesConfig`* Whether definitions of this type
should default to the `config` section of a module (see
[Example: Structure of NixOS Modules](#ex-module-syntax))
if it is an attribute set. Enabling this only has a benefit
when the submodule defines an option named `config` or `options`.
In such a case it would allow the option to be set with
`the-submodule.config = "value"` instead of requiring
`the-submodule.config.config = "value"`. This is because
only when modules *don\'t* set the `config` or `options`
keys, all keys are interpreted as option definitions in the
`config` section. Enabling this option implicitly puts all
attributes in the `config` section.
With this option enabled, defining a non-`config` section
requires using a function:
`the-submodule = { ... }: { options = { ... }; }`.
## Composed Types {#sec-option-types-composed}
Composed types are types that take a type as parameter. `listOf
int` and `either int str` are examples of composed types.
`types.listOf` *`t`*
: A list of *`t`* type, e.g. `types.listOf
int`. Multiple definitions are merged with list concatenation.
`types.attrsOf` *`t`*
: An attribute set of where all the values are of *`t`* type. Multiple
definitions result in the joined attribute set.
::: {.note}
This type is *strict* in its values, which in turn means attributes
cannot depend on other attributes. See `
types.lazyAttrsOf` for a lazy version.
:::
`types.lazyAttrsOf` *`t`*
: An attribute set of where all the values are of *`t`* type. Multiple
definitions result in the joined attribute set. This is the lazy
version of `types.attrsOf
`, allowing attributes to depend on each other.
::: {.warning}
This version does not fully support conditional definitions! With an
option `foo` of this type and a definition
`foo.attr = lib.mkIf false 10`, evaluating `foo ? attr` will return
`true` even though it should be false. Accessing the value will then
throw an error. For types *`t`* that have an `emptyValue` defined,
that value will be returned instead of throwing an error. So if the
type of `foo.attr` was `lazyAttrsOf (nullOr int)`, `null` would be
returned instead for the same `mkIf false` definition.
:::
`types.nullOr` *`t`*
: `null` or type *`t`*. Multiple definitions are merged according to
type *`t`*.
`types.uniq` *`t`*
: Ensures that type *`t`* cannot be merged. It is used to ensure option
definitions are declared only once.
`types.either` *`t1 t2`*
: Type *`t1`* or type *`t2`*, e.g. `with types; either int str`.
Multiple definitions cannot be merged.
`types.oneOf` \[ *`t1 t2`* \... \]
: Type *`t1`* or type *`t2`* and so forth, e.g.
`with types; oneOf [ int str bool ]`. Multiple definitions cannot be
merged.
`types.coercedTo` *`from f to`*
: Type *`to`* or type *`from`* which will be coerced to type *`to`* using
function *`f`* which takes an argument of type *`from`* and return a
value of type *`to`*. Can be used to preserve backwards compatibility
of an option if its type was changed.
## Submodule {#section-option-types-submodule}
`submodule` is a very powerful type that defines a set of sub-options
that are handled like a separate module.
It takes a parameter *`o`*, that should be a set, or a function returning
a set with an `options` key defining the sub-options. Submodule option
definitions are type-checked accordingly to the `options` declarations.
Of course, you can nest submodule option definitons for even higher
modularity.
The option set can be defined directly
([Example: Directly defined submodule](#ex-submodule-direct)) or as reference
([Example: Submodule defined as a reference](#ex-submodule-reference)).
::: {#ex-submodule-direct .example}
::: {.title}
**Example: Directly defined submodule**
:::
```nix
options.mod = mkOption {
description = "submodule example";
type = with types; submodule {
options = {
foo = mkOption {
type = int;
};
bar = mkOption {
type = str;
};
};
};
};
```
:::
::: {#ex-submodule-reference .example}
::: {.title}
**Example: Submodule defined as a reference**
:::
```nix
let
modOptions = {
options = {
foo = mkOption {
type = int;
};
bar = mkOption {
type = int;
};
};
};
in
options.mod = mkOption {
description = "submodule example";
type = with types; submodule modOptions;
};
```
:::
The `submodule` type is especially interesting when used with composed
types like `attrsOf` or `listOf`. When composed with `listOf`
([Example: Declaration of a list of submodules](#ex-submodule-listof-declaration)), `submodule` allows
multiple definitions of the submodule option set
([Example: Definition of a list of submodules](#ex-submodule-listof-definition)).
::: {#ex-submodule-listof-declaration .example}
::: {.title}
**Example: Declaration of a list of submodules**
:::
```nix
options.mod = mkOption {
description = "submodule example";
type = with types; listOf (submodule {
options = {
foo = mkOption {
type = int;
};
bar = mkOption {
type = str;
};
};
});
};
```
:::
::: {#ex-submodule-listof-definition .example}
::: {.title}
**Example: Definition of a list of submodules**
:::
```nix
config.mod = [
{ foo = 1; bar = "one"; }
{ foo = 2; bar = "two"; }
];
```
:::
When composed with `attrsOf`
([Example: Declaration of attribute sets of submodules](#ex-submodule-attrsof-declaration)), `submodule` allows
multiple named definitions of the submodule option set
([Example: Definition of attribute sets of submodules](#ex-submodule-attrsof-definition)).
::: {#ex-submodule-attrsof-declaration .example}
::: {.title}
**Example: Declaration of attribute sets of submodules**
:::
```nix
options.mod = mkOption {
description = "submodule example";
type = with types; attrsOf (submodule {
options = {
foo = mkOption {
type = int;
};
bar = mkOption {
type = str;
};
};
});
};
```
:::
::: {#ex-submodule-attrsof-definition .example}
::: {.title}
**Example: Definition of attribute sets of submodules**
:::
```nix
config.mod.one = { foo = 1; bar = "one"; };
config.mod.two = { foo = 2; bar = "two"; };
```
:::
## Extending types {#sec-option-types-extending}
Types are mainly characterized by their `check` and `merge` functions.
`check`
: The function to type check the value. Takes a value as parameter and
return a boolean. It is possible to extend a type check with the
`addCheck` function ([Example: Adding a type check](#ex-extending-type-check-1)),
or to fully override the check function
([Example: Overriding a type check](#ex-extending-type-check-2)).
::: {#ex-extending-type-check-1 .example}
::: {.title}
**Example: Adding a type check**
:::
```nix
byte = mkOption {
description = "An integer between 0 and 255.";
type = types.addCheck types.int (x: x >= 0 && x <= 255);
};
```
:::
::: {#ex-extending-type-check-2 .example}
::: {.title}
**Example: Overriding a type check**
:::
```nix
nixThings = mkOption {
description = "words that start with 'nix'";
type = types.str // {
check = (x: lib.hasPrefix "nix" x)
};
};
```
:::
`merge`
: Function to merge the options values when multiple values are set.
The function takes two parameters, `loc` the option path as a list
of strings, and `defs` the list of defined values as a list. It is
possible to override a type merge function for custom needs.
## Custom Types {#sec-option-types-custom}
Custom types can be created with the `mkOptionType` function. As type
creation includes some more complex topics such as submodule handling,
it is recommended to get familiar with `types.nix` code before creating
a new type.
The only required parameter is `name`.
`name`
: A string representation of the type function name.
`definition`
: Description of the type used in documentation. Give information of
the type and any of its arguments.
`check`
: A function to type check the definition value. Takes the definition
value as a parameter and returns a boolean indicating the type check
result, `true` for success and `false` for failure.
`merge`
: A function to merge multiple definitions values. Takes two
parameters:
*`loc`*
: The option path as a list of strings, e.g. `["boot" "loader
"grub" "enable"]`.
*`defs`*
: The list of sets of defined `value` and `file` where the value
was defined, e.g. `[ {
file = "/foo.nix"; value = 1; } { file = "/bar.nix"; value = 2 }
]`. The `merge` function should return the merged value
or throw an error in case the values are impossible or not meant
to be merged.
`getSubOptions`
: For composed types that can take a submodule as type parameter, this
function generate sub-options documentation. It takes the current
option prefix as a list and return the set of sub-options. Usually
defined in a recursive manner by adding a term to the prefix, e.g.
`prefix:
elemType.getSubOptions (prefix ++
["prefix"])` where *`"prefix"`* is the newly added prefix.
`getSubModules`
: For composed types that can take a submodule as type parameter, this
function should return the type parameters submodules. If the type
parameter is called `elemType`, the function should just recursively
look into submodules by returning `elemType.getSubModules;`.
`substSubModules`
: For composed types that can take a submodule as type parameter, this
function can be used to substitute the parameter of a submodule
type. It takes a module as parameter and return the type with the
submodule options substituted. It is usually defined as a type
function call with a recursive call to `substSubModules`, e.g for a
type `composedType` that take an `elemtype` type parameter, this
function should be defined as `m:
composedType (elemType.substSubModules m)`.
`typeMerge`
: A function to merge multiple type declarations. Takes the type to
merge `functor` as parameter. A `null` return value means that type
cannot be merged.
*`f`*
: The type to merge `functor`.
Note: There is a generic `defaultTypeMerge` that work with most of
value and composed types.
`functor`
: An attribute set representing the type. It is used for type
operations and has the following keys:
`type`
: The type function.
`wrapped`
: Holds the type parameter for composed types.
`payload`
: Holds the value parameter for value types. The types that have a
`payload` are the `enum`, `separatedString` and `submodule`
types.
`binOp`
: A binary operation that can merge the payloads of two same
types. Defined as a function that take two payloads as
parameters and return the payloads merged.

View file

@ -1,914 +0,0 @@
<section xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xi="http://www.w3.org/2001/XInclude"
version="5.0"
xml:id="sec-option-types">
<title>Options Types</title>
<para>
Option types are a way to put constraints on the values a module option can
take. Types are also responsible of how values are merged in case of multiple
value definitions.
</para>
<section xml:id="sec-option-types-basic">
<title>Basic Types</title>
<para>
Basic types are the simplest available types in the module system. Basic
types include multiple string types that mainly differ in how definition
merging is handled.
</para>
<variablelist>
<varlistentry>
<term>
<varname>types.bool</varname>
</term>
<listitem>
<para>
A boolean, its values can be <literal>true</literal> or
<literal>false</literal>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<varname>types.path</varname>
</term>
<listitem>
<para>
A filesystem path, defined as anything that when coerced to a string
starts with a slash. Even if derivations can be considered as path, the
more specific <literal>types.package</literal> should be preferred.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<varname>types.package</varname>
</term>
<listitem>
<para>
A derivation or a store path.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<varname>types.anything</varname>
</term>
<listitem>
<para>
A type that accepts any value and recursively merges attribute sets together.
This type is recommended when the option type is unknown.
<example xml:id="ex-types-anything">
<title><literal>types.anything</literal> Example</title>
<para>
Two definitions of this type like
<programlisting>
{
str = lib.mkDefault "foo";
pkg.hello = pkgs.hello;
fun.fun = x: x + 1;
}
</programlisting>
<programlisting>
{
str = lib.mkIf true "bar";
pkg.gcc = pkgs.gcc;
fun.fun = lib.mkForce (x: x + 2);
}
</programlisting>
will get merged to
<programlisting>
{
str = "bar";
pkg.gcc = pkgs.gcc;
pkg.hello = pkgs.hello;
fun.fun = x: x + 2;
}
</programlisting>
</para>
</example>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<varname>types.attrs</varname>
</term>
<listitem>
<para>
A free-form attribute set.
<warning><para>
This type will be deprecated in the future because it doesn't recurse
into attribute sets, silently drops earlier attribute definitions, and
doesn't discharge <literal>lib.mkDefault</literal>, <literal>lib.mkIf
</literal> and co. For allowing arbitrary attribute sets, prefer
<literal>types.attrsOf types.anything</literal> instead which doesn't
have these problems.
</para></warning>
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
Integer-related types:
</para>
<variablelist>
<varlistentry>
<term>
<varname>types.int</varname>
</term>
<listitem>
<para>
A signed integer.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<varname>types.ints.{s8, s16, s32}</varname>
</term>
<listitem>
<para>
Signed integers with a fixed length (8, 16 or 32 bits). They go from
<inlineequation><mathphrase>2<superscript>n</superscript>/2</mathphrase>
</inlineequation> to <inlineequation>
<mathphrase>2<superscript>n</superscript>/21</mathphrase>
</inlineequation> respectively (e.g. <literal>128</literal> to
<literal>127</literal> for 8 bits).
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<varname>types.ints.unsigned</varname>
</term>
<listitem>
<para>
An unsigned integer (that is >= 0).
</para>
</listitem>
</varlistentry>
<varlistentry xml:id='types.ints.ux'>
<term>
<varname>types.ints.{u8, u16, u32}</varname>
</term>
<listitem>
<para>
Unsigned integers with a fixed length (8, 16 or 32 bits). They go from
<inlineequation><mathphrase>0</mathphrase></inlineequation> to
<inlineequation>
<mathphrase>2<superscript>n</superscript>1</mathphrase>
</inlineequation> respectively (e.g. <literal>0</literal> to
<literal>255</literal> for 8 bits).
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<varname>types.ints.positive</varname>
</term>
<listitem>
<para>
A positive integer (that is > 0).
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<varname>types.port</varname>
</term>
<listitem>
<para>
A port number. This type is an alias to
<link linkend='types.ints.ux'><varname>types.ints.u16</varname></link>.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
String-related types:
</para>
<variablelist>
<varlistentry>
<term>
<varname>types.str</varname>
</term>
<listitem>
<para>
A string. Multiple definitions cannot be merged.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<varname>types.lines</varname>
</term>
<listitem>
<para>
A string. Multiple definitions are concatenated with a new line
<literal>"\n"</literal>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<varname>types.commas</varname>
</term>
<listitem>
<para>
A string. Multiple definitions are concatenated with a comma
<literal>","</literal>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<varname>types.envVar</varname>
</term>
<listitem>
<para>
A string. Multiple definitions are concatenated with a collon
<literal>":"</literal>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<varname>types.strMatching</varname>
</term>
<listitem>
<para>
A string matching a specific regular expression. Multiple definitions
cannot be merged. The regular expression is processed using
<literal>builtins.match</literal>.
</para>
</listitem>
</varlistentry>
</variablelist>
</section>
<section xml:id="sec-option-types-value">
<title>Value Types</title>
<para>
Value types are types that take a value parameter.
</para>
<variablelist>
<varlistentry>
<term>
<varname>types.enum</varname> <replaceable>l</replaceable>
</term>
<listitem>
<para>
One element of the list <replaceable>l</replaceable>, e.g.
<literal>types.enum [ "left" "right" ]</literal>. Multiple definitions
cannot be merged.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<varname>types.separatedString</varname> <replaceable>sep</replaceable>
</term>
<listitem>
<para>
A string with a custom separator <replaceable>sep</replaceable>, e.g.
<literal>types.separatedString "|"</literal>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<varname>types.ints.between</varname> <replaceable>lowest</replaceable> <replaceable>highest</replaceable>
</term>
<listitem>
<para>
An integer between <replaceable>lowest</replaceable> and
<replaceable>highest</replaceable> (both inclusive). Useful for creating
types like <literal>types.port</literal>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<varname>types.submodule</varname> <replaceable>o</replaceable>
</term>
<listitem>
<para>
A set of sub options <replaceable>o</replaceable>.
<replaceable>o</replaceable> can be an attribute set, a function
returning an attribute set, or a path to a file containing such a value. Submodules are used in
composed types to create modular options. This is equivalent to
<literal>types.submoduleWith { modules = toList o; shorthandOnlyDefinesConfig = true; }</literal>.
Submodules are detailed in
<xref
linkend='section-option-types-submodule' />.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<varname>types.submoduleWith</varname> {
<replaceable>modules</replaceable>,
<replaceable>specialArgs</replaceable> ? {},
<replaceable>shorthandOnlyDefinesConfig</replaceable> ? false }
</term>
<listitem>
<para>
Like <varname>types.submodule</varname>, but more flexible and with better defaults.
It has parameters
<itemizedlist>
<listitem><para>
<replaceable>modules</replaceable>
A list of modules to use by default for this submodule type. This gets combined
with all option definitions to build the final list of modules that will be included.
<note><para>
Only options defined with this argument are included in rendered documentation.
</para></note>
</para></listitem>
<listitem><para>
<replaceable>specialArgs</replaceable>
An attribute set of extra arguments to be passed to the module functions.
The option <literal>_module.args</literal> should be used instead
for most arguments since it allows overriding. <replaceable>specialArgs</replaceable> should only be
used for arguments that can&apos;t go through the module fixed-point, because of
infinite recursion or other problems. An example is overriding the
<varname>lib</varname> argument, because <varname>lib</varname> itself is used
to define <literal>_module.args</literal>, which makes using
<literal>_module.args</literal> to define it impossible.
</para></listitem>
<listitem><para>
<replaceable>shorthandOnlyDefinesConfig</replaceable>
Whether definitions of this type should default to the <literal>config</literal>
section of a module (see <xref linkend='ex-module-syntax'/>) if it is an attribute
set. Enabling this only has a benefit when the submodule defines an option named
<literal>config</literal> or <literal>options</literal>. In such a case it would
allow the option to be set with <literal>the-submodule.config = "value"</literal>
instead of requiring <literal>the-submodule.config.config = "value"</literal>.
This is because only when modules <emphasis>don&apos;t</emphasis> set the
<literal>config</literal> or <literal>options</literal> keys, all keys are interpreted
as option definitions in the <literal>config</literal> section. Enabling this option
implicitly puts all attributes in the <literal>config</literal> section.
</para>
<para>
With this option enabled, defining a non-<literal>config</literal> section requires
using a function: <literal>the-submodule = { ... }: { options = { ... }; }</literal>.
</para></listitem>
</itemizedlist>
</para>
</listitem>
</varlistentry>
</variablelist>
</section>
<section xml:id="sec-option-types-composed">
<title>Composed Types</title>
<para>
Composed types are types that take a type as parameter. <literal>listOf
int</literal> and <literal>either int str</literal> are examples of composed
types.
</para>
<variablelist>
<varlistentry>
<term>
<varname>types.listOf</varname> <replaceable>t</replaceable>
</term>
<listitem>
<para>
A list of <replaceable>t</replaceable> type, e.g. <literal>types.listOf
int</literal>. Multiple definitions are merged with list concatenation.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<varname>types.attrsOf</varname> <replaceable>t</replaceable>
</term>
<listitem>
<para>
An attribute set of where all the values are of
<replaceable>t</replaceable> type. Multiple definitions result in the
joined attribute set.
<note><para>
This type is <emphasis>strict</emphasis> in its values, which in turn
means attributes cannot depend on other attributes. See <varname>
types.lazyAttrsOf</varname> for a lazy version.
</para></note>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<varname>types.lazyAttrsOf</varname> <replaceable>t</replaceable>
</term>
<listitem>
<para>
An attribute set of where all the values are of
<replaceable>t</replaceable> type. Multiple definitions result in the
joined attribute set. This is the lazy version of <varname>types.attrsOf
</varname>, allowing attributes to depend on each other.
<warning><para>
This version does not fully support conditional definitions! With an
option <varname>foo</varname> of this type and a definition
<literal>foo.attr = lib.mkIf false 10</literal>, evaluating
<literal>foo ? attr</literal> will return <literal>true</literal>
even though it should be false. Accessing the value will then throw
an error. For types <replaceable>t</replaceable> that have an
<literal>emptyValue</literal> defined, that value will be returned
instead of throwing an error. So if the type of <literal>foo.attr</literal>
was <literal>lazyAttrsOf (nullOr int)</literal>, <literal>null</literal>
would be returned instead for the same <literal>mkIf false</literal> definition.
</para></warning>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<varname>types.nullOr</varname> <replaceable>t</replaceable>
</term>
<listitem>
<para>
<literal>null</literal> or type <replaceable>t</replaceable>. Multiple
definitions are merged according to type <replaceable>t</replaceable>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<varname>types.uniq</varname> <replaceable>t</replaceable>
</term>
<listitem>
<para>
Ensures that type <replaceable>t</replaceable> cannot be merged. It is
used to ensure option definitions are declared only once.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<varname>types.either</varname> <replaceable>t1</replaceable> <replaceable>t2</replaceable>
</term>
<listitem>
<para>
Type <replaceable>t1</replaceable> or type <replaceable>t2</replaceable>,
e.g. <literal>with types; either int str</literal>. Multiple definitions
cannot be merged.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<varname>types.oneOf</varname> [ <replaceable>t1</replaceable> <replaceable>t2</replaceable> ... ]
</term>
<listitem>
<para>
Type <replaceable>t1</replaceable> or type <replaceable>t2</replaceable> and so forth,
e.g. <literal>with types; oneOf [ int str bool ]</literal>. Multiple definitions
cannot be merged.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<varname>types.coercedTo</varname> <replaceable>from</replaceable> <replaceable>f</replaceable> <replaceable>to</replaceable>
</term>
<listitem>
<para>
Type <replaceable>to</replaceable> or type
<replaceable>from</replaceable> which will be coerced to type
<replaceable>to</replaceable> using function <replaceable>f</replaceable>
which takes an argument of type <replaceable>from</replaceable> and
return a value of type <replaceable>to</replaceable>. Can be used to
preserve backwards compatibility of an option if its type was changed.
</para>
</listitem>
</varlistentry>
</variablelist>
</section>
<section xml:id='section-option-types-submodule'>
<title>Submodule</title>
<para>
<literal>submodule</literal> is a very powerful type that defines a set of
sub-options that are handled like a separate module.
</para>
<para>
It takes a parameter <replaceable>o</replaceable>, that should be a set, or
a function returning a set with an <literal>options</literal> key defining
the sub-options. Submodule option definitions are type-checked accordingly
to the <literal>options</literal> declarations. Of course, you can nest
submodule option definitons for even higher modularity.
</para>
<para>
The option set can be defined directly
(<xref linkend='ex-submodule-direct' />) or as reference
(<xref linkend='ex-submodule-reference' />).
</para>
<example xml:id='ex-submodule-direct'>
<title>Directly defined submodule</title>
<screen>
options.mod = mkOption {
description = "submodule example";
type = with types; submodule {
options = {
foo = mkOption {
type = int;
};
bar = mkOption {
type = str;
};
};
};
};</screen>
</example>
<example xml:id='ex-submodule-reference'>
<title>Submodule defined as a reference</title>
<screen>
let
modOptions = {
options = {
foo = mkOption {
type = int;
};
bar = mkOption {
type = int;
};
};
};
in
options.mod = mkOption {
description = "submodule example";
type = with types; submodule modOptions;
};</screen>
</example>
<para>
The <literal>submodule</literal> type is especially interesting when used
with composed types like <literal>attrsOf</literal> or
<literal>listOf</literal>. When composed with <literal>listOf</literal>
(<xref linkend='ex-submodule-listof-declaration' />),
<literal>submodule</literal> allows multiple definitions of the submodule
option set (<xref linkend='ex-submodule-listof-definition' />).
</para>
<example xml:id='ex-submodule-listof-declaration'>
<title>Declaration of a list of submodules</title>
<screen>
options.mod = mkOption {
description = "submodule example";
type = with types; listOf (submodule {
options = {
foo = mkOption {
type = int;
};
bar = mkOption {
type = str;
};
};
});
};</screen>
</example>
<example xml:id='ex-submodule-listof-definition'>
<title>Definition of a list of submodules</title>
<screen>
config.mod = [
{ foo = 1; bar = "one"; }
{ foo = 2; bar = "two"; }
];</screen>
</example>
<para>
When composed with <literal>attrsOf</literal>
(<xref linkend='ex-submodule-attrsof-declaration' />),
<literal>submodule</literal> allows multiple named definitions of the
submodule option set (<xref linkend='ex-submodule-attrsof-definition' />).
</para>
<example xml:id='ex-submodule-attrsof-declaration'>
<title>Declaration of attribute sets of submodules</title>
<screen>
options.mod = mkOption {
description = "submodule example";
type = with types; attrsOf (submodule {
options = {
foo = mkOption {
type = int;
};
bar = mkOption {
type = str;
};
};
});
};</screen>
</example>
<example xml:id='ex-submodule-attrsof-definition'>
<title>Declaration of attribute sets of submodules</title>
<screen>
config.mod.one = { foo = 1; bar = "one"; };
config.mod.two = { foo = 2; bar = "two"; };</screen>
</example>
</section>
<section xml:id="sec-option-types-extending">
<title>Extending types</title>
<para>
Types are mainly characterized by their <literal>check</literal> and
<literal>merge</literal> functions.
</para>
<variablelist>
<varlistentry>
<term>
<varname>check</varname>
</term>
<listitem>
<para>
The function to type check the value. Takes a value as parameter and
return a boolean. It is possible to extend a type check with the
<literal>addCheck</literal> function
(<xref
linkend='ex-extending-type-check-1' />), or to fully
override the check function
(<xref linkend='ex-extending-type-check-2' />).
</para>
<example xml:id='ex-extending-type-check-1'>
<title>Adding a type check</title>
<screen>
byte = mkOption {
description = "An integer between 0 and 255.";
type = types.addCheck types.int (x: x &gt;= 0 &amp;&amp; x &lt;= 255);
};</screen>
</example>
<example xml:id='ex-extending-type-check-2'>
<title>Overriding a type check</title>
<screen>
nixThings = mkOption {
description = "words that start with 'nix'";
type = types.str // {
check = (x: lib.hasPrefix "nix" x)
};
};</screen>
</example>
</listitem>
</varlistentry>
<varlistentry>
<term>
<varname>merge</varname>
</term>
<listitem>
<para>
Function to merge the options values when multiple values are set. The
function takes two parameters, <literal>loc</literal> the option path as
a list of strings, and <literal>defs</literal> the list of defined values
as a list. It is possible to override a type merge function for custom
needs.
</para>
</listitem>
</varlistentry>
</variablelist>
</section>
<section xml:id="sec-option-types-custom">
<title>Custom Types</title>
<para>
Custom types can be created with the <literal>mkOptionType</literal>
function. As type creation includes some more complex topics such as
submodule handling, it is recommended to get familiar with
<filename
xlink:href="https://github.com/NixOS/nixpkgs/blob/master/lib/types.nix">types.nix</filename>
code before creating a new type.
</para>
<para>
The only required parameter is <literal>name</literal>.
</para>
<variablelist>
<varlistentry>
<term>
<varname>name</varname>
</term>
<listitem>
<para>
A string representation of the type function name.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<varname>definition</varname>
</term>
<listitem>
<para>
Description of the type used in documentation. Give information of the
type and any of its arguments.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<varname>check</varname>
</term>
<listitem>
<para>
A function to type check the definition value. Takes the definition value
as a parameter and returns a boolean indicating the type check result,
<literal>true</literal> for success and <literal>false</literal> for
failure.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<varname>merge</varname>
</term>
<listitem>
<para>
A function to merge multiple definitions values. Takes two parameters:
</para>
<variablelist>
<varlistentry>
<term>
<replaceable>loc</replaceable>
</term>
<listitem>
<para>
The option path as a list of strings, e.g. <literal>["boot" "loader
"grub" "enable"]</literal>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<replaceable>defs</replaceable>
</term>
<listitem>
<para>
The list of sets of defined <literal>value</literal> and
<literal>file</literal> where the value was defined, e.g. <literal>[ {
file = "/foo.nix"; value = 1; } { file = "/bar.nix"; value = 2 }
]</literal>. The <literal>merge</literal> function should return the
merged value or throw an error in case the values are impossible or
not meant to be merged.
</para>
</listitem>
</varlistentry>
</variablelist>
</listitem>
</varlistentry>
<varlistentry>
<term>
<varname>getSubOptions</varname>
</term>
<listitem>
<para>
For composed types that can take a submodule as type parameter, this
function generate sub-options documentation. It takes the current option
prefix as a list and return the set of sub-options. Usually defined in a
recursive manner by adding a term to the prefix, e.g. <literal>prefix:
elemType.getSubOptions (prefix ++
[<replaceable>"prefix"</replaceable>])</literal> where
<replaceable>"prefix"</replaceable> is the newly added prefix.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<varname>getSubModules</varname>
</term>
<listitem>
<para>
For composed types that can take a submodule as type parameter, this
function should return the type parameters submodules. If the type
parameter is called <literal>elemType</literal>, the function should just
recursively look into submodules by returning
<literal>elemType.getSubModules;</literal>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<varname>substSubModules</varname>
</term>
<listitem>
<para>
For composed types that can take a submodule as type parameter, this
function can be used to substitute the parameter of a submodule type. It
takes a module as parameter and return the type with the submodule
options substituted. It is usually defined as a type function call with a
recursive call to <literal>substSubModules</literal>, e.g for a type
<literal>composedType</literal> that take an <literal>elemtype</literal>
type parameter, this function should be defined as <literal>m:
composedType (elemType.substSubModules m)</literal>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<varname>typeMerge</varname>
</term>
<listitem>
<para>
A function to merge multiple type declarations. Takes the type to merge
<literal>functor</literal> as parameter. A <literal>null</literal> return
value means that type cannot be merged.
</para>
<variablelist>
<varlistentry>
<term>
<replaceable>f</replaceable>
</term>
<listitem>
<para>
The type to merge <literal>functor</literal>.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
Note: There is a generic <literal>defaultTypeMerge</literal> that work
with most of value and composed types.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<varname>functor</varname>
</term>
<listitem>
<para>
An attribute set representing the type. It is used for type operations
and has the following keys:
</para>
<variablelist>
<varlistentry>
<term>
<varname>type</varname>
</term>
<listitem>
<para>
The type function.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<varname>wrapped</varname>
</term>
<listitem>
<para>
Holds the type parameter for composed types.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<varname>payload</varname>
</term>
<listitem>
<para>
Holds the value parameter for value types. The types that have a
<literal>payload</literal> are the <literal>enum</literal>,
<literal>separatedString</literal> and <literal>submodule</literal>
types.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<varname>binOp</varname>
</term>
<listitem>
<para>
A binary operation that can merge the payloads of two same types.
Defined as a function that take two payloads as parameters and return
the payloads merged.
</para>
</listitem>
</varlistentry>
</variablelist>
</listitem>
</varlistentry>
</variablelist>
</section>
</section>

View file

@ -0,0 +1,64 @@
# Replace Modules {#sec-replace-modules}
Modules that are imported can also be disabled. The option declarations,
config implementation and the imports of a disabled module will be
ignored, allowing another to take it\'s place. This can be used to
import a set of modules from another channel while keeping the rest of
the system on a stable release.
`disabledModules` is a top level attribute like `imports`, `options` and
`config`. It contains a list of modules that will be disabled. This can
either be the full path to the module or a string with the filename
relative to the modules path (eg. \<nixpkgs/nixos/modules> for nixos).
This example will replace the existing postgresql module with the
version defined in the nixos-unstable channel while keeping the rest of
the modules and packages from the original nixos channel. This only
overrides the module definition, this won\'t use postgresql from
nixos-unstable unless explicitly configured to do so.
```nix
{ config, lib, pkgs, ... }:
{
disabledModules = [ "services/databases/postgresql.nix" ];
imports =
[ # Use postgresql service from nixos-unstable channel.
# sudo nix-channel --add https://nixos.org/channels/nixos-unstable nixos-unstable
<nixos-unstable/nixos/modules/services/databases/postgresql.nix>
];
services.postgresql.enable = true;
}
```
This example shows how to define a custom module as a replacement for an
existing module. Importing this module will disable the original module
without having to know it\'s implementation details.
```nix
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.programs.man;
in
{
disabledModules = [ "services/programs/man.nix" ];
options = {
programs.man.enable = mkOption {
type = types.bool;
default = true;
description = "Whether to enable manual pages.";
};
};
config = mkIf cfg.enabled {
warnings = [ "disabled manpages for production deployments." ];
};
}
```

View file

@ -1,79 +0,0 @@
<section xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xi="http://www.w3.org/2001/XInclude"
version="5.0"
xml:id="sec-replace-modules">
<title>Replace Modules</title>
<para>
Modules that are imported can also be disabled. The option declarations,
config implementation and the imports of a disabled module will be ignored, allowing another
to take it's place. This can be used to import a set of modules from another
channel while keeping the rest of the system on a stable release.
</para>
<para>
<literal>disabledModules</literal> is a top level attribute like
<literal>imports</literal>, <literal>options</literal> and
<literal>config</literal>. It contains a list of modules that will be
disabled. This can either be the full path to the module or a string with the
filename relative to the modules path (eg. &lt;nixpkgs/nixos/modules&gt; for
nixos).
</para>
<para>
This example will replace the existing postgresql module with the version
defined in the nixos-unstable channel while keeping the rest of the modules
and packages from the original nixos channel. This only overrides the module
definition, this won't use postgresql from nixos-unstable unless explicitly
configured to do so.
</para>
<programlisting>
{ config, lib, pkgs, ... }:
{
disabledModules = [ "services/databases/postgresql.nix" ];
imports =
[ # Use postgresql service from nixos-unstable channel.
# sudo nix-channel --add https://nixos.org/channels/nixos-unstable nixos-unstable
&lt;nixos-unstable/nixos/modules/services/databases/postgresql.nix&gt;
];
services.postgresql.enable = true;
}
</programlisting>
<para>
This example shows how to define a custom module as a replacement for an
existing module. Importing this module will disable the original module
without having to know it's implementation details.
</para>
<programlisting>
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.programs.man;
in
{
disabledModules = [ "services/programs/man.nix" ];
options = {
programs.man.enable = mkOption {
type = types.bool;
default = true;
description = "Whether to enable manual pages.";
};
};
config = mkIf cfg.enabled {
warnings = [ "disabled manpages for production deployments." ];
};
}
</programlisting>
</section>

View file

@ -0,0 +1,192 @@
# Options for Program Settings {#sec-settings-options}
Many programs have configuration files where program-specific settings
can be declared. File formats can be separated into two categories:
- Nix-representable ones: These can trivially be mapped to a subset of
Nix syntax. E.g. JSON is an example, since its values like
`{"foo":{"bar":10}}` can be mapped directly to Nix:
`{ foo = { bar = 10; }; }`. Other examples are INI, YAML and TOML.
The following section explains the convention for these settings.
- Non-nix-representable ones: These can\'t be trivially mapped to a
subset of Nix syntax. Most generic programming languages are in this
group, e.g. bash, since the statement `if true; then echo hi; fi`
doesn\'t have a trivial representation in Nix.
Currently there are no fixed conventions for these, but it is common
to have a `configFile` option for setting the configuration file
path directly. The default value of `configFile` can be an
auto-generated file, with convenient options for controlling the
contents. For example an option of type `attrsOf str` can be used
for representing environment variables which generates a section
like `export FOO="foo"`. Often it can also be useful to also include
an `extraConfig` option of type `lines` to allow arbitrary text
after the autogenerated part of the file.
## Nix-representable Formats (JSON, YAML, TOML, INI, \...) {#sec-settings-nix-representable}
By convention, formats like this are handled with a generic `settings`
option, representing the full program configuration as a Nix value. The
type of this option should represent the format. The most common formats
have a predefined type and string generator already declared under
`pkgs.formats`:
`pkgs.formats.json` { }
: A function taking an empty attribute set (for future extensibility)
and returning a set with JSON-specific attributes `type` and
`generate` as specified [below](#pkgs-formats-result).
`pkgs.formats.yaml` { }
: A function taking an empty attribute set (for future extensibility)
and returning a set with YAML-specific attributes `type` and
`generate` as specified [below](#pkgs-formats-result).
`pkgs.formats.ini` { *`listsAsDuplicateKeys`* ? false, *`listToValue`* ? null, \... }
: A function taking an attribute set with values
`listsAsDuplicateKeys`
: A boolean for controlling whether list values can be used to
represent duplicate INI keys
`listToValue`
: A function for turning a list of values into a single value.
It returns a set with INI-specific attributes `type` and `generate`
as specified [below](#pkgs-formats-result).
`pkgs.formats.toml` { }
: A function taking an empty attribute set (for future extensibility)
and returning a set with TOML-specific attributes `type` and
`generate` as specified [below](#pkgs-formats-result).
::: {#pkgs-formats-result}
These functions all return an attribute set with these values:
:::
`type`
: A module system type representing a value of the format
`generate` *`filename jsonValue`*
: A function that can render a value of the format to a file. Returns
a file path.
::: {.note}
This function puts the value contents in the Nix store. So this
should be avoided for secrets.
:::
::: {#ex-settings-nix-representable .example}
::: {.title}
**Example: Module with conventional `settings` option**
:::
The following shows a module for an example program that uses a JSON
configuration file. It demonstrates how above values can be used, along
with some other related best practices. See the comments for
explanations.
```nix
{ options, config, lib, pkgs, ... }:
let
cfg = config.services.foo;
# Define the settings format used for this program
settingsFormat = pkgs.formats.json {};
in {
options.services.foo = {
enable = lib.mkEnableOption "foo service";
settings = lib.mkOption {
# Setting this type allows for correct merging behavior
type = settingsFormat.type;
default = {};
description = ''
Configuration for foo, see
<link xlink:href="https://example.com/docs/foo"/>
for supported settings.
'';
};
};
config = lib.mkIf cfg.enable {
# We can assign some default settings here to make the service work by just
# enabling it. We use `mkDefault` for values that can be changed without
# problems
services.foo.settings = {
# Fails at runtime without any value set
log_level = lib.mkDefault "WARN";
# We assume systemd's `StateDirectory` is used, so we require this value,
# therefore no mkDefault
data_path = "/var/lib/foo";
# Since we use this to create a user we need to know the default value at
# eval time
user = lib.mkDefault "foo";
};
environment.etc."foo.json".source =
# The formats generator function takes a filename and the Nix value
# representing the format value and produces a filepath with that value
# rendered in the format
settingsFormat.generate "foo-config.json" cfg.settings;
# We know that the `user` attribute exists because we set a default value
# for it above, allowing us to use it without worries here
users.users.${cfg.settings.user} = { isSystemUser = true; };
# ...
};
}
```
:::
### Option declarations for attributes {#sec-settings-attrs-options}
Some `settings` attributes may deserve some extra care. They may need a
different type, default or merging behavior, or they are essential
options that should show their documentation in the manual. This can be
done using [](#sec-freeform-modules).
We extend above example using freeform modules to declare an option for
the port, which will enforce it to be a valid integer and make it show
up in the manual.
::: {#ex-settings-typed-attrs .example}
::: {.title}
**Example: Declaring a type-checked `settings` attribute**
:::
```nix
settings = lib.mkOption {
type = lib.types.submodule {
freeformType = settingsFormat.type;
# Declare an option for the port such that the type is checked and this option
# is shown in the manual.
options.port = lib.mkOption {
type = lib.types.port;
default = 8080;
description = ''
Which port this service should listen on.
'';
};
};
default = {};
description = ''
Configuration for Foo, see
<link xlink:href="https://example.com/docs/foo"/>
for supported values.
'';
};
```
:::

View file

@ -1,226 +0,0 @@
<section xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xi="http://www.w3.org/2001/XInclude"
version="5.0"
xml:id="sec-settings-options">
<title>Options for Program Settings</title>
<para>
Many programs have configuration files where program-specific settings can be declared. File formats can be separated into two categories:
<itemizedlist>
<listitem>
<para>
Nix-representable ones: These can trivially be mapped to a subset of Nix syntax. E.g. JSON is an example, since its values like <literal>{"foo":{"bar":10}}</literal> can be mapped directly to Nix: <literal>{ foo = { bar = 10; }; }</literal>. Other examples are INI, YAML and TOML. The following section explains the convention for these settings.
</para>
</listitem>
<listitem>
<para>
Non-nix-representable ones: These can't be trivially mapped to a subset of Nix syntax. Most generic programming languages are in this group, e.g. bash, since the statement <literal>if true; then echo hi; fi</literal> doesn't have a trivial representation in Nix.
</para>
<para>
Currently there are no fixed conventions for these, but it is common to have a <literal>configFile</literal> option for setting the configuration file path directly. The default value of <literal>configFile</literal> can be an auto-generated file, with convenient options for controlling the contents. For example an option of type <literal>attrsOf str</literal> can be used for representing environment variables which generates a section like <literal>export FOO="foo"</literal>. Often it can also be useful to also include an <literal>extraConfig</literal> option of type <literal>lines</literal> to allow arbitrary text after the autogenerated part of the file.
</para>
</listitem>
</itemizedlist>
</para>
<section xml:id="sec-settings-nix-representable">
<title>Nix-representable Formats (JSON, YAML, TOML, INI, ...)</title>
<para>
By convention, formats like this are handled with a generic <literal>settings</literal> option, representing the full program configuration as a Nix value. The type of this option should represent the format. The most common formats have a predefined type and string generator already declared under <literal>pkgs.formats</literal>:
<variablelist>
<varlistentry>
<term>
<varname>pkgs.formats.json</varname> { }
</term>
<listitem>
<para>
A function taking an empty attribute set (for future extensibility) and returning a set with JSON-specific attributes <varname>type</varname> and <varname>generate</varname> as specified <link linkend='pkgs-formats-result'>below</link>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<varname>pkgs.formats.yaml</varname> { }
</term>
<listitem>
<para>
A function taking an empty attribute set (for future extensibility) and returning a set with YAML-specific attributes <varname>type</varname> and <varname>generate</varname> as specified <link linkend='pkgs-formats-result'>below</link>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<varname>pkgs.formats.ini</varname> { <replaceable>listsAsDuplicateKeys</replaceable> ? false, <replaceable>listToValue</replaceable> ? null, ... }
</term>
<listitem>
<para>
A function taking an attribute set with values
<variablelist>
<varlistentry>
<term>
<varname>listsAsDuplicateKeys</varname>
</term>
<listitem>
<para>
A boolean for controlling whether list values can be used to represent duplicate INI keys
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<varname>listToValue</varname>
</term>
<listitem>
<para>
A function for turning a list of values into a single value.
</para>
</listitem>
</varlistentry>
</variablelist>
It returns a set with INI-specific attributes <varname>type</varname> and <varname>generate</varname> as specified <link linkend='pkgs-formats-result'>below</link>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<varname>pkgs.formats.toml</varname> { }
</term>
<listitem>
<para>
A function taking an empty attribute set (for future extensibility) and returning a set with TOML-specific attributes <varname>type</varname> and <varname>generate</varname> as specified <link linkend='pkgs-formats-result'>below</link>.
</para>
</listitem>
</varlistentry>
</variablelist>
</para>
<para xml:id="pkgs-formats-result">
These functions all return an attribute set with these values:
<variablelist>
<varlistentry>
<term>
<varname>type</varname>
</term>
<listitem>
<para>
A module system type representing a value of the format
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<varname>generate</varname> <replaceable>filename</replaceable> <replaceable>jsonValue</replaceable>
</term>
<listitem>
<para>
A function that can render a value of the format to a file. Returns a file path.
<note>
<para>
This function puts the value contents in the Nix store. So this should be avoided for secrets.
</para>
</note>
</para>
</listitem>
</varlistentry>
</variablelist>
</para>
<example xml:id="ex-settings-nix-representable">
<title>Module with conventional <literal>settings</literal> option</title>
<para>
The following shows a module for an example program that uses a JSON configuration file. It demonstrates how above values can be used, along with some other related best practices. See the comments for explanations.
</para>
<programlisting>
{ options, config, lib, pkgs, ... }:
let
cfg = config.services.foo;
# Define the settings format used for this program
settingsFormat = pkgs.formats.json {};
in {
options.services.foo = {
enable = lib.mkEnableOption "foo service";
settings = lib.mkOption {
# Setting this type allows for correct merging behavior
type = settingsFormat.type;
default = {};
description = ''
Configuration for foo, see
&lt;link xlink:href="https://example.com/docs/foo"/&gt;
for supported settings.
'';
};
};
config = lib.mkIf cfg.enable {
# We can assign some default settings here to make the service work by just
# enabling it. We use `mkDefault` for values that can be changed without
# problems
services.foo.settings = {
# Fails at runtime without any value set
log_level = lib.mkDefault "WARN";
# We assume systemd's `StateDirectory` is used, so we require this value,
# therefore no mkDefault
data_path = "/var/lib/foo";
# Since we use this to create a user we need to know the default value at
# eval time
user = lib.mkDefault "foo";
};
environment.etc."foo.json".source =
# The formats generator function takes a filename and the Nix value
# representing the format value and produces a filepath with that value
# rendered in the format
settingsFormat.generate "foo-config.json" cfg.settings;
# We know that the `user` attribute exists because we set a default value
# for it above, allowing us to use it without worries here
users.users.${cfg.settings.user} = { isSystemUser = true; };
# ...
};
}
</programlisting>
</example>
<section xml:id="sec-settings-attrs-options">
<title>Option declarations for attributes</title>
<para>
Some <literal>settings</literal> attributes may deserve some extra care. They may need a different type, default or merging behavior, or they are essential options that should show their documentation in the manual. This can be done using <xref linkend='sec-freeform-modules'/>.
<example xml:id="ex-settings-typed-attrs">
<title>Declaring a type-checked <literal>settings</literal> attribute</title>
<para>
We extend above example using freeform modules to declare an option for the port, which will enforce it to be a valid integer and make it show up in the manual.
</para>
<programlisting>
settings = lib.mkOption {
type = lib.types.submodule {
freeformType = settingsFormat.type;
# Declare an option for the port such that the type is checked and this option
# is shown in the manual.
options.port = lib.mkOption {
type = lib.types.port;
default = 8080;
description = ''
Which port this service should listen on.
'';
};
};
default = {};
description = ''
Configuration for Foo, see
&lt;link xlink:href="https://example.com/docs/foo"/&gt;
for supported values.
'';
};
</programlisting>
</example>
</para>
</section>
</section>
</section>

View file

@ -179,13 +179,13 @@ in {
}
</programlisting>
</example>
<xi:include href="option-declarations.xml" />
<xi:include href="option-types.xml" />
<xi:include href="option-def.xml" />
<xi:include href="../from_md/development/option-declarations.section.xml" />
<xi:include href="../from_md/development/option-types.section.xml" />
<xi:include href="../from_md/development/option-def.section.xml" />
<xi:include href="../from_md/development/assertions.section.xml" />
<xi:include href="meta-attributes.xml" />
<xi:include href="importing-modules.xml" />
<xi:include href="replace-modules.xml" />
<xi:include href="freeform-modules.xml" />
<xi:include href="settings-options.xml" />
<xi:include href="../from_md/development/meta-attributes.section.xml" />
<xi:include href="../from_md/development/importing-modules.section.xml" />
<xi:include href="../from_md/development/replace-modules.section.xml" />
<xi:include href="../from_md/development/freeform-modules.section.xml" />
<xi:include href="../from_md/development/settings-options.section.xml" />
</chapter>

View file

@ -0,0 +1,87 @@
<section xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" xml:id="sec-freeform-modules">
<title>Freeform modules</title>
<para>
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
<literal>attrsOf</literal> options in order to accept all attribute
names.
</para>
<para>
This feature can be enabled by using the attribute
<literal>freeformType</literal> 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
<literal>config</literal> set. Since this feature nullifies name
checking for entire option trees, it is only recommended for use in
submodules.
</para>
<anchor xml:id="ex-freeform-module" />
<para>
<emphasis role="strong">Example: Freeform submodule</emphasis>
</para>
<para>
The following shows a submodule assigning a freeform type that
allows arbitrary attributes with <literal>str</literal> values below
<literal>settings</literal>, but also declares an option for the
<literal>settings.port</literal> attribute to have it type-checked
and assign a default value. See
<link linkend="ex-settings-typed-attrs">Example: Declaring a
type-checked <literal>settings</literal> attribute</link> for a more
complete example.
</para>
<programlisting language="bash">
{ 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;
};
};
};
}
</programlisting>
<para>
And the following shows what such a module then allows
</para>
<programlisting language="bash">
{
# Not a declared option, but the freeform type allows this
settings.logLevel = &quot;debug&quot;;
# 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 = &quot;443&quot;;
}
</programlisting>
<note>
<para>
Freeform attributes cannot depend on other attributes of the same
set without infinite recursion:
</para>
<programlisting language="bash">
{
# This throws infinite recursion encountered
settings.logLevel = lib.mkIf (config.settings.port == 80) &quot;debug&quot;;
}
</programlisting>
<para>
To prevent this, declare options for all attributes that need to
depend on others. For above example this means to declare
<literal>logLevel</literal> to be an option.
</para>
</note>
</section>

View file

@ -0,0 +1,47 @@
<section xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" xml:id="sec-importing-modules">
<title>Importing Modules</title>
<para>
Sometimes NixOS modules need to be used in configuration but exist
outside of Nixpkgs. These modules can be imported:
</para>
<programlisting language="bash">
{ config, lib, pkgs, ... }:
{
imports =
[ # Use a locally-available module definition in
# ./example-module/default.nix
./example-module
];
services.exampleModule.enable = true;
}
</programlisting>
<para>
The environment variable <literal>NIXOS_EXTRA_MODULE_PATH</literal>
is an absolute path to a NixOS module that is included alongside the
Nixpkgs NixOS modules. Like any NixOS module, this module can import
additional modules:
</para>
<programlisting language="bash">
# ./module-list/default.nix
[
./example-module1
./example-module2
]
</programlisting>
<programlisting language="bash">
# ./extra-module/default.nix
{ imports = import ./module-list.nix; }
</programlisting>
<programlisting language="bash">
# NIXOS_EXTRA_MODULE_PATH=/absolute/path/to/extra-module
{ config, lib, pkgs, ... }:
{
# No `imports` needed
services.exampleModule1.enable = true;
}
</programlisting>
</section>

View file

@ -0,0 +1,55 @@
<section xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" xml:id="sec-meta-attributes">
<title>Meta Attributes</title>
<para>
Like Nix packages, NixOS modules can declare meta-attributes to
provide extra information. Module meta attributes are defined in the
<literal>meta.nix</literal> special module.
</para>
<para>
<literal>meta</literal> is a top level attribute like
<literal>options</literal> and <literal>config</literal>. Available
meta-attributes are <literal>maintainers</literal> and
<literal>doc</literal>.
</para>
<para>
Each of the meta-attributes must be defined at most once per module
file.
</para>
<programlisting language="bash">
{ config, lib, pkgs, ... }:
{
options = {
...
};
config = {
...
};
meta = {
maintainers = with lib.maintainers; [ ericsagnes ];
doc = ./default.xml;
};
}
</programlisting>
<itemizedlist>
<listitem>
<para>
<literal>maintainers</literal> contains a list of the module
maintainers.
</para>
</listitem>
<listitem>
<para>
<literal>doc</literal> points to a valid DocBook file containing
the module documentation. Its contents is automatically added to
<xref linkend="ch-configuration" />. Changes to a module
documentation have to be checked to not break building the NixOS
manual:
</para>
<programlisting>
$ nix-build nixos/release.nix -A manual.x86_64-linux
</programlisting>
</listitem>
</itemizedlist>
</section>

View file

@ -0,0 +1,203 @@
<section xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" xml:id="sec-option-declarations">
<title>Option Declarations</title>
<para>
An option declaration specifies the name, type and description of a
NixOS configuration option. It is invalid to define an option that
hasnt been declared in any module. An option declaration generally
looks like this:
</para>
<programlisting language="bash">
options = {
name = mkOption {
type = type specification;
default = default value;
example = example value;
description = &quot;Description for use in the NixOS manual.&quot;;
};
};
</programlisting>
<para>
The attribute names within the <literal>name</literal> attribute
path must be camel cased in general but should, as an exception,
match the
<link xlink:href="https://nixos.org/nixpkgs/manual/#sec-package-naming">
package attribute name</link> when referencing a Nixpkgs package.
For example, the option
<literal>services.nix-serve.bindAddress</literal> references the
<literal>nix-serve</literal> Nixpkgs package.
</para>
<para>
The function <literal>mkOption</literal> accepts the following
arguments.
</para>
<variablelist>
<varlistentry>
<term>
<literal>type</literal>
</term>
<listitem>
<para>
The type of the option (see
<xref linkend="sec-option-types" />). It may be omitted, but
thats not advisable since it may lead to errors that are hard
to diagnose.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<literal>default</literal>
</term>
<listitem>
<para>
The default value used if no value is defined by any module. A
default is not required; but if a default is not given, then
users of the module will have to define the value of the
option, otherwise an error will be thrown.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<literal>example</literal>
</term>
<listitem>
<para>
An example value that will be shown in the NixOS manual.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<literal>description</literal>
</term>
<listitem>
<para>
A textual description of the option, in DocBook format, that
will be included in the NixOS manual.
</para>
</listitem>
</varlistentry>
</variablelist>
<section xml:id="sec-option-declarations-eot">
<title>Extensible Option Types</title>
<para>
Extensible option types is a feature that allow to extend certain
types declaration through multiple module files. This feature only
work with a restricted set of types, namely
<literal>enum</literal> and <literal>submodules</literal> and any
composed forms of them.
</para>
<para>
Extensible option types can be used for <literal>enum</literal>
options that affects multiple modules, or as an alternative to
related <literal>enable</literal> options.
</para>
<para>
As an example, we will take the case of display managers. There is
a central display manager module for generic display manager
options and a module file per display manager backend (sddm, gdm
...).
</para>
<para>
There are two approach to this module structure:
</para>
<itemizedlist>
<listitem>
<para>
Managing the display managers independently by adding an
enable option to every display manager module backend. (NixOS)
</para>
</listitem>
<listitem>
<para>
Managing the display managers in the central module by adding
an option to select which display manager backend to use.
</para>
</listitem>
</itemizedlist>
<para>
Both approaches have problems.
</para>
<para>
Making backends independent can quickly become hard to manage. For
display managers, there can be only one enabled at a time, but the
type system can not enforce this restriction as there is no
relation between each backend <literal>enable</literal> option. As
a result, this restriction has to be done explicitely by adding
assertions in each display manager backend module.
</para>
<para>
On the other hand, managing the display managers backends in the
central module will require to change the central module option
every time a new backend is added or removed.
</para>
<para>
By using extensible option types, it is possible to create a
placeholder option in the central module
(<link linkend="ex-option-declaration-eot-service">Example:
Extensible type placeholder in the service module</link>), and to
extend it in each backend module
(<link linkend="ex-option-declaration-eot-backend-gdm">Example:
Extending
<literal>services.xserver.displayManager.enable</literal> in the
<literal>gdm</literal> module</link>,
<link linkend="ex-option-declaration-eot-backend-sddm">Example:
Extending
<literal>services.xserver.displayManager.enable</literal> in the
<literal>sddm</literal> module</link>).
</para>
<para>
As a result, <literal>displayManager.enable</literal> option
values can be added without changing the main service module file
and the type system automatically enforce that there can only be a
single display manager enabled.
</para>
<anchor xml:id="ex-option-declaration-eot-service" />
<para>
<emphasis role="strong">Example: Extensible type placeholder in
the service module</emphasis>
</para>
<programlisting language="bash">
services.xserver.displayManager.enable = mkOption {
description = &quot;Display manager to use&quot;;
type = with types; nullOr (enum [ ]);
};
</programlisting>
<anchor xml:id="ex-option-declaration-eot-backend-gdm" />
<para>
<emphasis role="strong">Example: Extending
<literal>services.xserver.displayManager.enable</literal> in the
<literal>gdm</literal> module</emphasis>
</para>
<programlisting language="bash">
services.xserver.displayManager.enable = mkOption {
type = with types; nullOr (enum [ &quot;gdm&quot; ]);
};
</programlisting>
<anchor xml:id="ex-option-declaration-eot-backend-sddm" />
<para>
<emphasis role="strong">Example: Extending
<literal>services.xserver.displayManager.enable</literal> in the
<literal>sddm</literal> module</emphasis>
</para>
<programlisting language="bash">
services.xserver.displayManager.enable = mkOption {
type = with types; nullOr (enum [ &quot;sddm&quot; ]);
};
</programlisting>
<para>
The placeholder declaration is a standard
<literal>mkOption</literal> declaration, but it is important that
extensible option declarations only use the
<literal>type</literal> argument.
</para>
<para>
Extensible option types work with any of the composed variants of
<literal>enum</literal> such as
<literal>with types; nullOr (enum [ &quot;foo&quot; &quot;bar&quot; ])</literal>
or
<literal>with types; listOf (enum [ &quot;foo&quot; &quot;bar&quot; ])</literal>.
</para>
</section>
</section>

View file

@ -0,0 +1,104 @@
<section xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" xml:id="sec-option-definitions">
<title>Option Definitions</title>
<para>
Option definitions are generally straight-forward bindings of values
to option names, like
</para>
<programlisting language="bash">
config = {
services.httpd.enable = true;
};
</programlisting>
<para>
However, sometimes you need to wrap an option definition or set of
option definitions in a <emphasis>property</emphasis> to achieve
certain effects:
</para>
<section xml:id="sec-option-definitions-delaying-conditionals">
<title>Delaying Conditionals</title>
<para>
If a set of option definitions is conditional on the value of
another option, you may need to use <literal>mkIf</literal>.
Consider, for instance:
</para>
<programlisting language="bash">
config = if config.services.httpd.enable then {
environment.systemPackages = [ ... ];
...
} else {};
</programlisting>
<para>
This definition will cause Nix to fail with an <quote>infinite
recursion</quote> error. Why? Because the value of
<literal>config.services.httpd.enable</literal> depends on the
value being constructed here. After all, you could also write the
clearly circular and contradictory:
</para>
<programlisting language="bash">
config = if config.services.httpd.enable then {
services.httpd.enable = false;
} else {
services.httpd.enable = true;
};
</programlisting>
<para>
The solution is to write:
</para>
<programlisting language="bash">
config = mkIf config.services.httpd.enable {
environment.systemPackages = [ ... ];
...
};
</programlisting>
<para>
The special function <literal>mkIf</literal> causes the evaluation
of the conditional to be <quote>pushed down</quote> into the
individual definitions, as if you had written:
</para>
<programlisting language="bash">
config = {
environment.systemPackages = if config.services.httpd.enable then [ ... ] else [];
...
};
</programlisting>
</section>
<section xml:id="sec-option-definitions-setting-priorities">
<title>Setting Priorities</title>
<para>
A module can override the definitions of an option in other
modules by setting a <emphasis>priority</emphasis>. All option
definitions that do not have the lowest priority value are
discarded. By default, option definitions have priority 1000. You
can specify an explicit priority by using
<literal>mkOverride</literal>, e.g.
</para>
<programlisting language="bash">
services.openssh.enable = mkOverride 10 false;
</programlisting>
<para>
This definition causes all other definitions with priorities above
10 to be discarded. The function <literal>mkForce</literal> is
equal to <literal>mkOverride 50</literal>.
</para>
</section>
<section xml:id="sec-option-definitions-merging">
<title>Merging Configurations</title>
<para>
In conjunction with <literal>mkIf</literal>, it is sometimes
useful for a module to return multiple sets of option definitions,
to be merged together as if they were declared in separate
modules. This can be done using <literal>mkMerge</literal>:
</para>
<programlisting language="bash">
config = mkMerge
[ # Unconditional stuff.
{ environment.systemPackages = [ ... ];
}
# Conditional stuff.
(mkIf config.services.bla.enable {
environment.systemPackages = [ ... ];
})
];
</programlisting>
</section>
</section>

View file

@ -0,0 +1,987 @@
<section xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" xml:id="sec-option-types">
<title>Options Types</title>
<para>
Option types are a way to put constraints on the values a module
option can take. Types are also responsible of how values are merged
in case of multiple value definitions.
</para>
<section xml:id="sec-option-types-basic">
<title>Basic Types</title>
<para>
Basic types are the simplest available types in the module system.
Basic types include multiple string types that mainly differ in
how definition merging is handled.
</para>
<variablelist>
<varlistentry>
<term>
<literal>types.bool</literal>
</term>
<listitem>
<para>
A boolean, its values can be <literal>true</literal> or
<literal>false</literal>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<literal>types.path</literal>
</term>
<listitem>
<para>
A filesystem path, defined as anything that when coerced to
a string starts with a slash. Even if derivations can be
considered as path, the more specific
<literal>types.package</literal> should be preferred.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<literal>types.package</literal>
</term>
<listitem>
<para>
A derivation or a store path.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<literal>types.anything</literal>
</term>
<listitem>
<para>
A type that accepts any value and recursively merges
attribute sets together. This type is recommended when the
option type is unknown.
</para>
<anchor xml:id="ex-types-anything" />
<para>
<emphasis role="strong">Example:
<literal>types.anything</literal> Example</emphasis>
</para>
<para>
Two definitions of this type like
</para>
<programlisting language="bash">
{
str = lib.mkDefault &quot;foo&quot;;
pkg.hello = pkgs.hello;
fun.fun = x: x + 1;
}
</programlisting>
<programlisting language="bash">
{
str = lib.mkIf true &quot;bar&quot;;
pkg.gcc = pkgs.gcc;
fun.fun = lib.mkForce (x: x + 2);
}
</programlisting>
<para>
will get merged to
</para>
<programlisting language="bash">
{
str = &quot;bar&quot;;
pkg.gcc = pkgs.gcc;
pkg.hello = pkgs.hello;
fun.fun = x: x + 2;
}
</programlisting>
</listitem>
</varlistentry>
<varlistentry>
<term>
<literal>types.attrs</literal>
</term>
<listitem>
<para>
A free-form attribute set.
</para>
<warning>
<para>
This type will be deprecated in the future because it
doesn't recurse into attribute sets, silently drops
earlier attribute definitions, and doesn't discharge
<literal>lib.mkDefault</literal>,
<literal>lib.mkIf</literal> and co. For allowing arbitrary
attribute sets, prefer
<literal>types.attrsOf types.anything</literal> instead
which doesn't have these problems.
</para>
</warning>
</listitem>
</varlistentry>
</variablelist>
<para>
Integer-related types:
</para>
<variablelist>
<varlistentry>
<term>
<literal>types.int</literal>
</term>
<listitem>
<para>
A signed integer.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<literal>types.ints.{s8, s16, s32}</literal>
</term>
<listitem>
<para>
Signed integers with a fixed length (8, 16 or 32 bits). They
go from 2^n/2 to 2^n/21 respectively (e.g.
<literal>128</literal> to <literal>127</literal> for 8
bits).
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<literal>types.ints.unsigned</literal>
</term>
<listitem>
<para>
An unsigned integer (that is &gt;= 0).
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<literal>types.ints.{u8, u16, u32}</literal>
</term>
<listitem>
<para>
Unsigned integers with a fixed length (8, 16 or 32 bits).
They go from 0 to 2^n1 respectively (e.g.
<literal>0</literal> to <literal>255</literal> for 8 bits).
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<literal>types.ints.positive</literal>
</term>
<listitem>
<para>
A positive integer (that is &gt; 0).
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<literal>types.port</literal>
</term>
<listitem>
<para>
A port number. This type is an alias to
<literal>types.ints.u16</literal>.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
String-related types:
</para>
<variablelist>
<varlistentry>
<term>
<literal>types.str</literal>
</term>
<listitem>
<para>
A string. Multiple definitions cannot be merged.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<literal>types.lines</literal>
</term>
<listitem>
<para>
A string. Multiple definitions are concatenated with a new
line <literal>&quot;\n&quot;</literal>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<literal>types.commas</literal>
</term>
<listitem>
<para>
A string. Multiple definitions are concatenated with a comma
<literal>&quot;,&quot;</literal>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<literal>types.envVar</literal>
</term>
<listitem>
<para>
A string. Multiple definitions are concatenated with a
collon <literal>&quot;:&quot;</literal>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<literal>types.strMatching</literal>
</term>
<listitem>
<para>
A string matching a specific regular expression. Multiple
definitions cannot be merged. The regular expression is
processed using <literal>builtins.match</literal>.
</para>
</listitem>
</varlistentry>
</variablelist>
</section>
<section xml:id="sec-option-types-value">
<title>Value Types</title>
<para>
Value types are types that take a value parameter.
</para>
<variablelist>
<varlistentry>
<term>
<literal>types.enum</literal>
<emphasis><literal>l</literal></emphasis>
</term>
<listitem>
<para>
One element of the list
<emphasis><literal>l</literal></emphasis>, e.g.
<literal>types.enum [ &quot;left&quot; &quot;right&quot; ]</literal>.
Multiple definitions cannot be merged.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<literal>types.separatedString</literal>
<emphasis><literal>sep</literal></emphasis>
</term>
<listitem>
<para>
A string with a custom separator
<emphasis><literal>sep</literal></emphasis>, e.g.
<literal>types.separatedString &quot;|&quot;</literal>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<literal>types.ints.between</literal>
<emphasis><literal>lowest highest</literal></emphasis>
</term>
<listitem>
<para>
An integer between
<emphasis><literal>lowest</literal></emphasis> and
<emphasis><literal>highest</literal></emphasis> (both
inclusive). Useful for creating types like
<literal>types.port</literal>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<literal>types.submodule</literal>
<emphasis><literal>o</literal></emphasis>
</term>
<listitem>
<para>
A set of sub options
<emphasis><literal>o</literal></emphasis>.
<emphasis><literal>o</literal></emphasis> can be an
attribute set, a function returning an attribute set, or a
path to a file containing such a value. Submodules are used
in composed types to create modular options. This is
equivalent to
<literal>types.submoduleWith { modules = toList o; shorthandOnlyDefinesConfig = true; }</literal>.
Submodules are detailed in
<link linkend="section-option-types-submodule">Submodule</link>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<literal>types.submoduleWith</literal> {
<emphasis><literal>modules</literal></emphasis>,
<emphasis><literal>specialArgs</literal></emphasis> ? {},
<emphasis><literal>shorthandOnlyDefinesConfig</literal></emphasis>
? false }
</term>
<listitem>
<para>
Like <literal>types.submodule</literal>, but more flexible
and with better defaults. It has parameters
</para>
<itemizedlist>
<listitem>
<para>
<emphasis><literal>modules</literal></emphasis> A list
of modules to use by default for this submodule type.
This gets combined with all option definitions to build
the final list of modules that will be included.
</para>
<note>
<para>
Only options defined with this argument are included
in rendered documentation.
</para>
</note>
</listitem>
<listitem>
<para>
<emphasis><literal>specialArgs</literal></emphasis> An
attribute set of extra arguments to be passed to the
module functions. The option
<literal>_module.args</literal> should be used instead
for most arguments since it allows overriding.
<emphasis><literal>specialArgs</literal></emphasis>
should only be used for arguments that can't go through
the module fixed-point, because of infinite recursion or
other problems. An example is overriding the
<literal>lib</literal> argument, because
<literal>lib</literal> itself is used to define
<literal>_module.args</literal>, which makes using
<literal>_module.args</literal> to define it impossible.
</para>
</listitem>
<listitem>
<para>
<emphasis><literal>shorthandOnlyDefinesConfig</literal></emphasis>
Whether definitions of this type should default to the
<literal>config</literal> section of a module (see
<link linkend="ex-module-syntax">Example: Structure of
NixOS Modules</link>) if it is an attribute set.
Enabling this only has a benefit when the submodule
defines an option named <literal>config</literal> or
<literal>options</literal>. In such a case it would
allow the option to be set with
<literal>the-submodule.config = &quot;value&quot;</literal>
instead of requiring
<literal>the-submodule.config.config = &quot;value&quot;</literal>.
This is because only when modules
<emphasis>don't</emphasis> set the
<literal>config</literal> or <literal>options</literal>
keys, all keys are interpreted as option definitions in
the <literal>config</literal> section. Enabling this
option implicitly puts all attributes in the
<literal>config</literal> section.
</para>
<para>
With this option enabled, defining a
non-<literal>config</literal> section requires using a
function:
<literal>the-submodule = { ... }: { options = { ... }; }</literal>.
</para>
</listitem>
</itemizedlist>
</listitem>
</varlistentry>
</variablelist>
</section>
<section xml:id="sec-option-types-composed">
<title>Composed Types</title>
<para>
Composed types are types that take a type as parameter.
<literal>listOf int</literal> and
<literal>either int str</literal> are examples of composed types.
</para>
<variablelist>
<varlistentry>
<term>
<literal>types.listOf</literal>
<emphasis><literal>t</literal></emphasis>
</term>
<listitem>
<para>
A list of <emphasis><literal>t</literal></emphasis> type,
e.g. <literal>types.listOf int</literal>. Multiple
definitions are merged with list concatenation.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<literal>types.attrsOf</literal>
<emphasis><literal>t</literal></emphasis>
</term>
<listitem>
<para>
An attribute set of where all the values are of
<emphasis><literal>t</literal></emphasis> type. Multiple
definitions result in the joined attribute set.
</para>
<note>
<para>
This type is <emphasis>strict</emphasis> in its values,
which in turn means attributes cannot depend on other
attributes. See <literal> types.lazyAttrsOf</literal> for
a lazy version.
</para>
</note>
</listitem>
</varlistentry>
<varlistentry>
<term>
<literal>types.lazyAttrsOf</literal>
<emphasis><literal>t</literal></emphasis>
</term>
<listitem>
<para>
An attribute set of where all the values are of
<emphasis><literal>t</literal></emphasis> type. Multiple
definitions result in the joined attribute set. This is the
lazy version of <literal>types.attrsOf </literal>, allowing
attributes to depend on each other.
</para>
<warning>
<para>
This version does not fully support conditional
definitions! With an option <literal>foo</literal> of this
type and a definition
<literal>foo.attr = lib.mkIf false 10</literal>,
evaluating <literal>foo ? attr</literal> will return
<literal>true</literal> even though it should be false.
Accessing the value will then throw an error. For types
<emphasis><literal>t</literal></emphasis> that have an
<literal>emptyValue</literal> defined, that value will be
returned instead of throwing an error. So if the type of
<literal>foo.attr</literal> was
<literal>lazyAttrsOf (nullOr int)</literal>,
<literal>null</literal> would be returned instead for the
same <literal>mkIf false</literal> definition.
</para>
</warning>
</listitem>
</varlistentry>
<varlistentry>
<term>
<literal>types.nullOr</literal>
<emphasis><literal>t</literal></emphasis>
</term>
<listitem>
<para>
<literal>null</literal> or type
<emphasis><literal>t</literal></emphasis>. Multiple
definitions are merged according to type
<emphasis><literal>t</literal></emphasis>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<literal>types.uniq</literal>
<emphasis><literal>t</literal></emphasis>
</term>
<listitem>
<para>
Ensures that type <emphasis><literal>t</literal></emphasis>
cannot be merged. It is used to ensure option definitions
are declared only once.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<literal>types.either</literal>
<emphasis><literal>t1 t2</literal></emphasis>
</term>
<listitem>
<para>
Type <emphasis><literal>t1</literal></emphasis> or type
<emphasis><literal>t2</literal></emphasis>, e.g.
<literal>with types; either int str</literal>. Multiple
definitions cannot be merged.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<literal>types.oneOf</literal> [
<emphasis><literal>t1 t2</literal></emphasis> ... ]
</term>
<listitem>
<para>
Type <emphasis><literal>t1</literal></emphasis> or type
<emphasis><literal>t2</literal></emphasis> and so forth,
e.g. <literal>with types; oneOf [ int str bool ]</literal>.
Multiple definitions cannot be merged.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<literal>types.coercedTo</literal>
<emphasis><literal>from f to</literal></emphasis>
</term>
<listitem>
<para>
Type <emphasis><literal>to</literal></emphasis> or type
<emphasis><literal>from</literal></emphasis> which will be
coerced to type <emphasis><literal>to</literal></emphasis>
using function <emphasis><literal>f</literal></emphasis>
which takes an argument of type
<emphasis><literal>from</literal></emphasis> and return a
value of type <emphasis><literal>to</literal></emphasis>.
Can be used to preserve backwards compatibility of an option
if its type was changed.
</para>
</listitem>
</varlistentry>
</variablelist>
</section>
<section xml:id="section-option-types-submodule">
<title>Submodule</title>
<para>
<literal>submodule</literal> is a very powerful type that defines
a set of sub-options that are handled like a separate module.
</para>
<para>
It takes a parameter <emphasis><literal>o</literal></emphasis>,
that should be a set, or a function returning a set with an
<literal>options</literal> key defining the sub-options. Submodule
option definitions are type-checked accordingly to the
<literal>options</literal> declarations. Of course, you can nest
submodule option definitons for even higher modularity.
</para>
<para>
The option set can be defined directly
(<link linkend="ex-submodule-direct">Example: Directly defined
submodule</link>) or as reference
(<link linkend="ex-submodule-reference">Example: Submodule defined
as a reference</link>).
</para>
<anchor xml:id="ex-submodule-direct" />
<para>
<emphasis role="strong">Example: Directly defined
submodule</emphasis>
</para>
<programlisting language="bash">
options.mod = mkOption {
description = &quot;submodule example&quot;;
type = with types; submodule {
options = {
foo = mkOption {
type = int;
};
bar = mkOption {
type = str;
};
};
};
};
</programlisting>
<anchor xml:id="ex-submodule-reference" />
<para>
<emphasis role="strong">Example: Submodule defined as a
reference</emphasis>
</para>
<programlisting language="bash">
let
modOptions = {
options = {
foo = mkOption {
type = int;
};
bar = mkOption {
type = int;
};
};
};
in
options.mod = mkOption {
description = &quot;submodule example&quot;;
type = with types; submodule modOptions;
};
</programlisting>
<para>
The <literal>submodule</literal> type is especially interesting
when used with composed types like <literal>attrsOf</literal> or
<literal>listOf</literal>. When composed with
<literal>listOf</literal>
(<link linkend="ex-submodule-listof-declaration">Example:
Declaration of a list of submodules</link>),
<literal>submodule</literal> allows multiple definitions of the
submodule option set
(<link linkend="ex-submodule-listof-definition">Example:
Definition of a list of submodules</link>).
</para>
<anchor xml:id="ex-submodule-listof-declaration" />
<para>
<emphasis role="strong">Example: Declaration of a list of
submodules</emphasis>
</para>
<programlisting language="bash">
options.mod = mkOption {
description = &quot;submodule example&quot;;
type = with types; listOf (submodule {
options = {
foo = mkOption {
type = int;
};
bar = mkOption {
type = str;
};
};
});
};
</programlisting>
<anchor xml:id="ex-submodule-listof-definition" />
<para>
<emphasis role="strong">Example: Definition of a list of
submodules</emphasis>
</para>
<programlisting language="bash">
config.mod = [
{ foo = 1; bar = &quot;one&quot;; }
{ foo = 2; bar = &quot;two&quot;; }
];
</programlisting>
<para>
When composed with <literal>attrsOf</literal>
(<link linkend="ex-submodule-attrsof-declaration">Example:
Declaration of attribute sets of submodules</link>),
<literal>submodule</literal> allows multiple named definitions of
the submodule option set
(<link linkend="ex-submodule-attrsof-definition">Example:
Definition of attribute sets of submodules</link>).
</para>
<anchor xml:id="ex-submodule-attrsof-declaration" />
<para>
<emphasis role="strong">Example: Declaration of attribute sets of
submodules</emphasis>
</para>
<programlisting language="bash">
options.mod = mkOption {
description = &quot;submodule example&quot;;
type = with types; attrsOf (submodule {
options = {
foo = mkOption {
type = int;
};
bar = mkOption {
type = str;
};
};
});
};
</programlisting>
<anchor xml:id="ex-submodule-attrsof-definition" />
<para>
<emphasis role="strong">Example: Definition of attribute sets of
submodules</emphasis>
</para>
<programlisting language="bash">
config.mod.one = { foo = 1; bar = &quot;one&quot;; };
config.mod.two = { foo = 2; bar = &quot;two&quot;; };
</programlisting>
</section>
<section xml:id="sec-option-types-extending">
<title>Extending types</title>
<para>
Types are mainly characterized by their <literal>check</literal>
and <literal>merge</literal> functions.
</para>
<variablelist>
<varlistentry>
<term>
<literal>check</literal>
</term>
<listitem>
<para>
The function to type check the value. Takes a value as
parameter and return a boolean. It is possible to extend a
type check with the <literal>addCheck</literal> function
(<link linkend="ex-extending-type-check-1">Example: Adding a
type check</link>), or to fully override the check function
(<link linkend="ex-extending-type-check-2">Example:
Overriding a type check</link>).
</para>
<anchor xml:id="ex-extending-type-check-1" />
<para>
<emphasis role="strong">Example: Adding a type
check</emphasis>
</para>
<programlisting language="bash">
byte = mkOption {
description = &quot;An integer between 0 and 255.&quot;;
type = types.addCheck types.int (x: x &gt;= 0 &amp;&amp; x &lt;= 255);
};
</programlisting>
<anchor xml:id="ex-extending-type-check-2" />
<para>
<emphasis role="strong">Example: Overriding a type
check</emphasis>
</para>
<programlisting language="bash">
nixThings = mkOption {
description = &quot;words that start with 'nix'&quot;;
type = types.str // {
check = (x: lib.hasPrefix &quot;nix&quot; x)
};
};
</programlisting>
</listitem>
</varlistentry>
<varlistentry>
<term>
<literal>merge</literal>
</term>
<listitem>
<para>
Function to merge the options values when multiple values
are set. The function takes two parameters,
<literal>loc</literal> the option path as a list of strings,
and <literal>defs</literal> the list of defined values as a
list. It is possible to override a type merge function for
custom needs.
</para>
</listitem>
</varlistentry>
</variablelist>
</section>
<section xml:id="sec-option-types-custom">
<title>Custom Types</title>
<para>
Custom types can be created with the
<literal>mkOptionType</literal> function. As type creation
includes some more complex topics such as submodule handling, it
is recommended to get familiar with <literal>types.nix</literal>
code before creating a new type.
</para>
<para>
The only required parameter is <literal>name</literal>.
</para>
<variablelist>
<varlistentry>
<term>
<literal>name</literal>
</term>
<listitem>
<para>
A string representation of the type function name.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<literal>definition</literal>
</term>
<listitem>
<para>
Description of the type used in documentation. Give
information of the type and any of its arguments.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<literal>check</literal>
</term>
<listitem>
<para>
A function to type check the definition value. Takes the
definition value as a parameter and returns a boolean
indicating the type check result, <literal>true</literal>
for success and <literal>false</literal> for failure.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<literal>merge</literal>
</term>
<listitem>
<para>
A function to merge multiple definitions values. Takes two
parameters:
</para>
<variablelist>
<varlistentry>
<term>
<emphasis><literal>loc</literal></emphasis>
</term>
<listitem>
<para>
The option path as a list of strings, e.g.
<literal>[&quot;boot&quot; &quot;loader &quot;grub&quot; &quot;enable&quot;]</literal>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<emphasis><literal>defs</literal></emphasis>
</term>
<listitem>
<para>
The list of sets of defined <literal>value</literal>
and <literal>file</literal> where the value was
defined, e.g.
<literal>[ { file = &quot;/foo.nix&quot;; value = 1; } { file = &quot;/bar.nix&quot;; value = 2 } ]</literal>.
The <literal>merge</literal> function should return
the merged value or throw an error in case the values
are impossible or not meant to be merged.
</para>
</listitem>
</varlistentry>
</variablelist>
</listitem>
</varlistentry>
<varlistentry>
<term>
<literal>getSubOptions</literal>
</term>
<listitem>
<para>
For composed types that can take a submodule as type
parameter, this function generate sub-options documentation.
It takes the current option prefix as a list and return the
set of sub-options. Usually defined in a recursive manner by
adding a term to the prefix, e.g.
<literal>prefix: elemType.getSubOptions (prefix ++ [&quot;prefix&quot;])</literal>
where
<emphasis><literal>&quot;prefix&quot;</literal></emphasis>
is the newly added prefix.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<literal>getSubModules</literal>
</term>
<listitem>
<para>
For composed types that can take a submodule as type
parameter, this function should return the type parameters
submodules. If the type parameter is called
<literal>elemType</literal>, the function should just
recursively look into submodules by returning
<literal>elemType.getSubModules;</literal>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<literal>substSubModules</literal>
</term>
<listitem>
<para>
For composed types that can take a submodule as type
parameter, this function can be used to substitute the
parameter of a submodule type. It takes a module as
parameter and return the type with the submodule options
substituted. It is usually defined as a type function call
with a recursive call to <literal>substSubModules</literal>,
e.g for a type <literal>composedType</literal> that take an
<literal>elemtype</literal> type parameter, this function
should be defined as
<literal>m: composedType (elemType.substSubModules m)</literal>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<literal>typeMerge</literal>
</term>
<listitem>
<para>
A function to merge multiple type declarations. Takes the
type to merge <literal>functor</literal> as parameter. A
<literal>null</literal> return value means that type cannot
be merged.
</para>
<variablelist>
<varlistentry>
<term>
<emphasis><literal>f</literal></emphasis>
</term>
<listitem>
<para>
The type to merge <literal>functor</literal>.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
Note: There is a generic <literal>defaultTypeMerge</literal>
that work with most of value and composed types.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<literal>functor</literal>
</term>
<listitem>
<para>
An attribute set representing the type. It is used for type
operations and has the following keys:
</para>
<variablelist>
<varlistentry>
<term>
<literal>type</literal>
</term>
<listitem>
<para>
The type function.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<literal>wrapped</literal>
</term>
<listitem>
<para>
Holds the type parameter for composed types.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<literal>payload</literal>
</term>
<listitem>
<para>
Holds the value parameter for value types. The types
that have a <literal>payload</literal> are the
<literal>enum</literal>,
<literal>separatedString</literal> and
<literal>submodule</literal> types.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<literal>binOp</literal>
</term>
<listitem>
<para>
A binary operation that can merge the payloads of two
same types. Defined as a function that take two
payloads as parameters and return the payloads merged.
</para>
</listitem>
</varlistentry>
</variablelist>
</listitem>
</varlistentry>
</variablelist>
</section>
</section>

View file

@ -0,0 +1,70 @@
<section xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" xml:id="sec-replace-modules">
<title>Replace Modules</title>
<para>
Modules that are imported can also be disabled. The option
declarations, config implementation and the imports of a disabled
module will be ignored, allowing another to take it's place. This
can be used to import a set of modules from another channel while
keeping the rest of the system on a stable release.
</para>
<para>
<literal>disabledModules</literal> is a top level attribute like
<literal>imports</literal>, <literal>options</literal> and
<literal>config</literal>. It contains a list of modules that will
be disabled. This can either be the full path to the module or a
string with the filename relative to the modules path (eg.
&lt;nixpkgs/nixos/modules&gt; for nixos).
</para>
<para>
This example will replace the existing postgresql module with the
version defined in the nixos-unstable channel while keeping the rest
of the modules and packages from the original nixos channel. This
only overrides the module definition, this won't use postgresql from
nixos-unstable unless explicitly configured to do so.
</para>
<programlisting language="bash">
{ config, lib, pkgs, ... }:
{
disabledModules = [ &quot;services/databases/postgresql.nix&quot; ];
imports =
[ # Use postgresql service from nixos-unstable channel.
# sudo nix-channel --add https://nixos.org/channels/nixos-unstable nixos-unstable
&lt;nixos-unstable/nixos/modules/services/databases/postgresql.nix&gt;
];
services.postgresql.enable = true;
}
</programlisting>
<para>
This example shows how to define a custom module as a replacement
for an existing module. Importing this module will disable the
original module without having to know it's implementation details.
</para>
<programlisting language="bash">
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.programs.man;
in
{
disabledModules = [ &quot;services/programs/man.nix&quot; ];
options = {
programs.man.enable = mkOption {
type = types.bool;
default = true;
description = &quot;Whether to enable manual pages.&quot;;
};
};
config = mkIf cfg.enabled {
warnings = [ &quot;disabled manpages for production deployments.&quot; ];
};
}
</programlisting>
</section>

View file

@ -0,0 +1,285 @@
<section xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" xml:id="sec-settings-options">
<title>Options for Program Settings</title>
<para>
Many programs have configuration files where program-specific
settings can be declared. File formats can be separated into two
categories:
</para>
<itemizedlist>
<listitem>
<para>
Nix-representable ones: These can trivially be mapped to a
subset of Nix syntax. E.g. JSON is an example, since its values
like <literal>{&quot;foo&quot;:{&quot;bar&quot;:10}}</literal>
can be mapped directly to Nix:
<literal>{ foo = { bar = 10; }; }</literal>. Other examples are
INI, YAML and TOML. The following section explains the
convention for these settings.
</para>
</listitem>
<listitem>
<para>
Non-nix-representable ones: These can't be trivially mapped to a
subset of Nix syntax. Most generic programming languages are in
this group, e.g. bash, since the statement
<literal>if true; then echo hi; fi</literal> doesn't have a
trivial representation in Nix.
</para>
<para>
Currently there are no fixed conventions for these, but it is
common to have a <literal>configFile</literal> option for
setting the configuration file path directly. The default value
of <literal>configFile</literal> can be an auto-generated file,
with convenient options for controlling the contents. For
example an option of type <literal>attrsOf str</literal> can be
used for representing environment variables which generates a
section like <literal>export FOO=&quot;foo&quot;</literal>.
Often it can also be useful to also include an
<literal>extraConfig</literal> option of type
<literal>lines</literal> to allow arbitrary text after the
autogenerated part of the file.
</para>
</listitem>
</itemizedlist>
<section xml:id="sec-settings-nix-representable">
<title>Nix-representable Formats (JSON, YAML, TOML, INI,
...)</title>
<para>
By convention, formats like this are handled with a generic
<literal>settings</literal> option, representing the full program
configuration as a Nix value. The type of this option should
represent the format. The most common formats have a predefined
type and string generator already declared under
<literal>pkgs.formats</literal>:
</para>
<variablelist>
<varlistentry>
<term>
<literal>pkgs.formats.json</literal> { }
</term>
<listitem>
<para>
A function taking an empty attribute set (for future
extensibility) and returning a set with JSON-specific
attributes <literal>type</literal> and
<literal>generate</literal> as specified
<link linkend="pkgs-formats-result">below</link>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<literal>pkgs.formats.yaml</literal> { }
</term>
<listitem>
<para>
A function taking an empty attribute set (for future
extensibility) and returning a set with YAML-specific
attributes <literal>type</literal> and
<literal>generate</literal> as specified
<link linkend="pkgs-formats-result">below</link>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<literal>pkgs.formats.ini</literal> {
<emphasis><literal>listsAsDuplicateKeys</literal></emphasis> ?
false, <emphasis><literal>listToValue</literal></emphasis> ?
null, ... }
</term>
<listitem>
<para>
A function taking an attribute set with values
</para>
<variablelist>
<varlistentry>
<term>
<literal>listsAsDuplicateKeys</literal>
</term>
<listitem>
<para>
A boolean for controlling whether list values can be
used to represent duplicate INI keys
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<literal>listToValue</literal>
</term>
<listitem>
<para>
A function for turning a list of values into a single
value.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
It returns a set with INI-specific attributes
<literal>type</literal> and <literal>generate</literal> as
specified <link linkend="pkgs-formats-result">below</link>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<literal>pkgs.formats.toml</literal> { }
</term>
<listitem>
<para>
A function taking an empty attribute set (for future
extensibility) and returning a set with TOML-specific
attributes <literal>type</literal> and
<literal>generate</literal> as specified
<link linkend="pkgs-formats-result">below</link>.
</para>
</listitem>
</varlistentry>
</variablelist>
<para xml:id="pkgs-formats-result">
These functions all return an attribute set with these values:
</para>
<variablelist>
<varlistentry>
<term>
<literal>type</literal>
</term>
<listitem>
<para>
A module system type representing a value of the format
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<literal>generate</literal>
<emphasis><literal>filename jsonValue</literal></emphasis>
</term>
<listitem>
<para>
A function that can render a value of the format to a file.
Returns a file path.
</para>
<note>
<para>
This function puts the value contents in the Nix store. So
this should be avoided for secrets.
</para>
</note>
</listitem>
</varlistentry>
</variablelist>
<anchor xml:id="ex-settings-nix-representable" />
<para>
<emphasis role="strong">Example: Module with conventional
<literal>settings</literal> option</emphasis>
</para>
<para>
The following shows a module for an example program that uses a
JSON configuration file. It demonstrates how above values can be
used, along with some other related best practices. See the
comments for explanations.
</para>
<programlisting language="bash">
{ options, config, lib, pkgs, ... }:
let
cfg = config.services.foo;
# Define the settings format used for this program
settingsFormat = pkgs.formats.json {};
in {
options.services.foo = {
enable = lib.mkEnableOption &quot;foo service&quot;;
settings = lib.mkOption {
# Setting this type allows for correct merging behavior
type = settingsFormat.type;
default = {};
description = ''
Configuration for foo, see
&lt;link xlink:href=&quot;https://example.com/docs/foo&quot;/&gt;
for supported settings.
'';
};
};
config = lib.mkIf cfg.enable {
# We can assign some default settings here to make the service work by just
# enabling it. We use `mkDefault` for values that can be changed without
# problems
services.foo.settings = {
# Fails at runtime without any value set
log_level = lib.mkDefault &quot;WARN&quot;;
# We assume systemd's `StateDirectory` is used, so we require this value,
# therefore no mkDefault
data_path = &quot;/var/lib/foo&quot;;
# Since we use this to create a user we need to know the default value at
# eval time
user = lib.mkDefault &quot;foo&quot;;
};
environment.etc.&quot;foo.json&quot;.source =
# The formats generator function takes a filename and the Nix value
# representing the format value and produces a filepath with that value
# rendered in the format
settingsFormat.generate &quot;foo-config.json&quot; cfg.settings;
# We know that the `user` attribute exists because we set a default value
# for it above, allowing us to use it without worries here
users.users.${cfg.settings.user} = { isSystemUser = true; };
# ...
};
}
</programlisting>
<section xml:id="sec-settings-attrs-options">
<title>Option declarations for attributes</title>
<para>
Some <literal>settings</literal> attributes may deserve some
extra care. They may need a different type, default or merging
behavior, or they are essential options that should show their
documentation in the manual. This can be done using
<xref linkend="sec-freeform-modules" />.
</para>
<para>
We extend above example using freeform modules to declare an
option for the port, which will enforce it to be a valid integer
and make it show up in the manual.
</para>
<anchor xml:id="ex-settings-typed-attrs" />
<para>
<emphasis role="strong">Example: Declaring a type-checked
<literal>settings</literal> attribute</emphasis>
</para>
<programlisting language="bash">
settings = lib.mkOption {
type = lib.types.submodule {
freeformType = settingsFormat.type;
# Declare an option for the port such that the type is checked and this option
# is shown in the manual.
options.port = lib.mkOption {
type = lib.types.port;
default = 8080;
description = ''
Which port this service should listen on.
'';
};
};
default = {};
description = ''
Configuration for Foo, see
&lt;link xlink:href=&quot;https://example.com/docs/foo&quot;/&gt;
for supported values.
'';
};
</programlisting>
</section>
</section>
</section>