1<section xmlns="http://docbook.org/ns/docbook"
2 xmlns:xlink="http://www.w3.org/1999/xlink"
3 xmlns:xi="http://www.w3.org/2001/XInclude"
4 version="5.0"
5 xml:id="sec-option-declarations">
6
7<title>Option Declarations</title>
8
9<para>An option declaration specifies the name, type and description
10of a NixOS configuration option. It is invalid to define an option
11that hasn’t been declared in any module. An option declaration
12generally looks like this:
13
14<programlisting>
15options = {
16 <replaceable>name</replaceable> = mkOption {
17 type = <replaceable>type specification</replaceable>;
18 default = <replaceable>default value</replaceable>;
19 example = <replaceable>example value</replaceable>;
20 description = "<replaceable>Description for use in the NixOS manual.</replaceable>";
21 };
22};
23</programlisting>
24
25The attribute names within the <replaceable>name</replaceable>
26attribute path must be camel cased in general but should, as an
27exception, match the
28<link
29xlink:href="https://nixos.org/nixpkgs/manual/#sec-package-naming">
30package attribute name</link> when referencing a Nixpkgs package. For
31example, the option <varname>services.nix-serve.bindAddress</varname>
32references the <varname>nix-serve</varname> Nixpkgs package.
33
34</para>
35
36<para>The function <varname>mkOption</varname> accepts the following arguments.
37
38<variablelist>
39
40 <varlistentry>
41 <term><varname>type</varname></term>
42 <listitem>
43 <para>The type of the option (see <xref linkend='sec-option-types' />).
44 It may be omitted, but that’s not advisable since it may lead to errors
45 that are hard to diagnose.</para>
46 </listitem>
47 </varlistentry>
48
49 <varlistentry>
50 <term><varname>default</varname></term>
51 <listitem>
52 <para>The default value used if no value is defined by any
53 module. A default is not required; but if a default is not given,
54 then users of the module will have to define the value of the
55 option, otherwise an error will be thrown.</para>
56 </listitem>
57 </varlistentry>
58
59 <varlistentry>
60 <term><varname>example</varname></term>
61 <listitem>
62 <para>An example value that will be shown in the NixOS manual.</para>
63 </listitem>
64 </varlistentry>
65
66 <varlistentry>
67 <term><varname>description</varname></term>
68 <listitem>
69 <para>A textual description of the option, in DocBook format,
70 that will be included in the NixOS manual.</para>
71 </listitem>
72 </varlistentry>
73
74</variablelist>
75
76</para>
77
78<section xml:id="sec-option-declarations-eot"><title>Extensible Option
79 Types</title>
80
81 <para>Extensible option types is a feature that allow to extend certain types
82 declaration through multiple module files.
83 This feature only work with a restricted set of types, namely
84 <literal>enum</literal> and <literal>submodules</literal> and any composed
85 forms of them.</para>
86
87 <para>Extensible option types can be used for <literal>enum</literal> options
88 that affects multiple modules, or as an alternative to related
89 <literal>enable</literal> options.</para>
90
91 <para>As an example, we will take the case of display managers. There is a
92 central display manager module for generic display manager options and a
93 module file per display manager backend (slim, sddm, gdm ...).
94 </para>
95
96 <para>There are two approach to this module structure:
97
98 <itemizedlist>
99 <listitem><para>Managing the display managers independently by adding an
100 enable option to every display manager module backend. (NixOS)</para>
101 </listitem>
102 <listitem><para>Managing the display managers in the central module by
103 adding an option to select which display manager backend to use.</para>
104 </listitem>
105 </itemizedlist>
106 </para>
107
108 <para>Both approaches have problems.</para>
109
110 <para>Making backends independent can quickly become hard to manage. For
111 display managers, there can be only one enabled at a time, but the type
112 system can not enforce this restriction as there is no relation between
113 each backend <literal>enable</literal> option. As a result, this restriction
114 has to be done explicitely by adding assertions in each display manager
115 backend module.</para>
116
117 <para>On the other hand, managing the display managers backends in the
118 central module will require to change the central module option every time
119 a new backend is added or removed.</para>
120
121 <para>By using extensible option types, it is possible to create a placeholder
122 option in the central module (<xref linkend='ex-option-declaration-eot-service'
123 />), and to extend it in each backend module (<xref
124 linkend='ex-option-declaration-eot-backend-slim' />, <xref
125 linkend='ex-option-declaration-eot-backend-sddm' />).</para>
126
127 <para>As a result, <literal>displayManager.enable</literal> option values can
128 be added without changing the main service module file and the type system
129 automatically enforce that there can only be a single display manager
130 enabled.</para>
131
132<example xml:id='ex-option-declaration-eot-service'><title>Extensible type
133 placeholder in the service module</title>
134<screen>
135services.xserver.displayManager.enable = mkOption {
136 description = "Display manager to use";
137 type = with types; nullOr (enum [ ]);
138};</screen></example>
139
140<example xml:id='ex-option-declaration-eot-backend-slim'><title>Extending
141 <literal>services.xserver.displayManager.enable</literal> in the
142 <literal>slim</literal> module</title>
143<screen>
144services.xserver.displayManager.enable = mkOption {
145 type = with types; nullOr (enum [ "slim" ]);
146};</screen></example>
147
148<example xml:id='ex-option-declaration-eot-backend-sddm'><title>Extending
149 <literal>services.xserver.displayManager.enable</literal> in the
150 <literal>sddm</literal> module</title>
151<screen>
152services.xserver.displayManager.enable = mkOption {
153 type = with types; nullOr (enum [ "sddm" ]);
154};</screen></example>
155
156<para>The placeholder declaration is a standard <literal>mkOption</literal>
157 declaration, but it is important that extensible option declarations only use
158 the <literal>type</literal> argument.</para>
159
160<para>Extensible option types work with any of the composed variants of
161 <literal>enum</literal> such as
162 <literal>with types; nullOr (enum [ "foo" "bar" ])</literal>
163 or <literal>with types; listOf (enum [ "foo" "bar" ])</literal>.</para>
164
165</section>
166</section>