1<section xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" xml:id="sec-settings-options">
2 <title>Options for Program Settings</title>
3 <para>
4 Many programs have configuration files where program-specific
5 settings can be declared. File formats can be separated into two
6 categories:
7 </para>
8 <itemizedlist>
9 <listitem>
10 <para>
11 Nix-representable ones: These can trivially be mapped to a
12 subset of Nix syntax. E.g. JSON is an example, since its values
13 like <literal>{"foo":{"bar":10}}</literal>
14 can be mapped directly to Nix:
15 <literal>{ foo = { bar = 10; }; }</literal>. Other examples are
16 INI, YAML and TOML. The following section explains the
17 convention for these settings.
18 </para>
19 </listitem>
20 <listitem>
21 <para>
22 Non-nix-representable ones: These can't be trivially mapped to a
23 subset of Nix syntax. Most generic programming languages are in
24 this group, e.g. bash, since the statement
25 <literal>if true; then echo hi; fi</literal> doesn't have a
26 trivial representation in Nix.
27 </para>
28 <para>
29 Currently there are no fixed conventions for these, but it is
30 common to have a <literal>configFile</literal> option for
31 setting the configuration file path directly. The default value
32 of <literal>configFile</literal> can be an auto-generated file,
33 with convenient options for controlling the contents. For
34 example an option of type <literal>attrsOf str</literal> can be
35 used for representing environment variables which generates a
36 section like <literal>export FOO="foo"</literal>.
37 Often it can also be useful to also include an
38 <literal>extraConfig</literal> option of type
39 <literal>lines</literal> to allow arbitrary text after the
40 autogenerated part of the file.
41 </para>
42 </listitem>
43 </itemizedlist>
44 <section xml:id="sec-settings-nix-representable">
45 <title>Nix-representable Formats (JSON, YAML, TOML, INI,
46 ...)</title>
47 <para>
48 By convention, formats like this are handled with a generic
49 <literal>settings</literal> option, representing the full program
50 configuration as a Nix value. The type of this option should
51 represent the format. The most common formats have a predefined
52 type and string generator already declared under
53 <literal>pkgs.formats</literal>:
54 </para>
55 <variablelist>
56 <varlistentry>
57 <term>
58 <literal>pkgs.formats.json</literal> { }
59 </term>
60 <listitem>
61 <para>
62 A function taking an empty attribute set (for future
63 extensibility) and returning a set with JSON-specific
64 attributes <literal>type</literal> and
65 <literal>generate</literal> as specified
66 <link linkend="pkgs-formats-result">below</link>.
67 </para>
68 </listitem>
69 </varlistentry>
70 <varlistentry>
71 <term>
72 <literal>pkgs.formats.yaml</literal> { }
73 </term>
74 <listitem>
75 <para>
76 A function taking an empty attribute set (for future
77 extensibility) and returning a set with YAML-specific
78 attributes <literal>type</literal> and
79 <literal>generate</literal> as specified
80 <link linkend="pkgs-formats-result">below</link>.
81 </para>
82 </listitem>
83 </varlistentry>
84 <varlistentry>
85 <term>
86 <literal>pkgs.formats.ini</literal> {
87 <emphasis><literal>listsAsDuplicateKeys</literal></emphasis> ?
88 false, <emphasis><literal>listToValue</literal></emphasis> ?
89 null, ... }
90 </term>
91 <listitem>
92 <para>
93 A function taking an attribute set with values
94 </para>
95 <variablelist>
96 <varlistentry>
97 <term>
98 <literal>listsAsDuplicateKeys</literal>
99 </term>
100 <listitem>
101 <para>
102 A boolean for controlling whether list values can be
103 used to represent duplicate INI keys
104 </para>
105 </listitem>
106 </varlistentry>
107 <varlistentry>
108 <term>
109 <literal>listToValue</literal>
110 </term>
111 <listitem>
112 <para>
113 A function for turning a list of values into a single
114 value.
115 </para>
116 </listitem>
117 </varlistentry>
118 </variablelist>
119 <para>
120 It returns a set with INI-specific attributes
121 <literal>type</literal> and <literal>generate</literal> as
122 specified <link linkend="pkgs-formats-result">below</link>.
123 </para>
124 </listitem>
125 </varlistentry>
126 <varlistentry>
127 <term>
128 <literal>pkgs.formats.toml</literal> { }
129 </term>
130 <listitem>
131 <para>
132 A function taking an empty attribute set (for future
133 extensibility) and returning a set with TOML-specific
134 attributes <literal>type</literal> and
135 <literal>generate</literal> as specified
136 <link linkend="pkgs-formats-result">below</link>.
137 </para>
138 </listitem>
139 </varlistentry>
140 </variablelist>
141 <para xml:id="pkgs-formats-result">
142 These functions all return an attribute set with these values:
143 </para>
144 <variablelist>
145 <varlistentry>
146 <term>
147 <literal>type</literal>
148 </term>
149 <listitem>
150 <para>
151 A module system type representing a value of the format
152 </para>
153 </listitem>
154 </varlistentry>
155 <varlistentry>
156 <term>
157 <literal>generate</literal>
158 <emphasis><literal>filename jsonValue</literal></emphasis>
159 </term>
160 <listitem>
161 <para>
162 A function that can render a value of the format to a file.
163 Returns a file path.
164 </para>
165 <note>
166 <para>
167 This function puts the value contents in the Nix store. So
168 this should be avoided for secrets.
169 </para>
170 </note>
171 </listitem>
172 </varlistentry>
173 </variablelist>
174 <anchor xml:id="ex-settings-nix-representable" />
175 <para>
176 <emphasis role="strong">Example: Module with conventional
177 <literal>settings</literal> option</emphasis>
178 </para>
179 <para>
180 The following shows a module for an example program that uses a
181 JSON configuration file. It demonstrates how above values can be
182 used, along with some other related best practices. See the
183 comments for explanations.
184 </para>
185 <programlisting language="bash">
186{ options, config, lib, pkgs, ... }:
187let
188 cfg = config.services.foo;
189 # Define the settings format used for this program
190 settingsFormat = pkgs.formats.json {};
191in {
192
193 options.services.foo = {
194 enable = lib.mkEnableOption "foo service";
195
196 settings = lib.mkOption {
197 # Setting this type allows for correct merging behavior
198 type = settingsFormat.type;
199 default = {};
200 description = ''
201 Configuration for foo, see
202 <link xlink:href="https://example.com/docs/foo"/>
203 for supported settings.
204 '';
205 };
206 };
207
208 config = lib.mkIf cfg.enable {
209 # We can assign some default settings here to make the service work by just
210 # enabling it. We use `mkDefault` for values that can be changed without
211 # problems
212 services.foo.settings = {
213 # Fails at runtime without any value set
214 log_level = lib.mkDefault "WARN";
215
216 # We assume systemd's `StateDirectory` is used, so we require this value,
217 # therefore no mkDefault
218 data_path = "/var/lib/foo";
219
220 # Since we use this to create a user we need to know the default value at
221 # eval time
222 user = lib.mkDefault "foo";
223 };
224
225 environment.etc."foo.json".source =
226 # The formats generator function takes a filename and the Nix value
227 # representing the format value and produces a filepath with that value
228 # rendered in the format
229 settingsFormat.generate "foo-config.json" cfg.settings;
230
231 # We know that the `user` attribute exists because we set a default value
232 # for it above, allowing us to use it without worries here
233 users.users.${cfg.settings.user} = { isSystemUser = true; };
234
235 # ...
236 };
237}
238</programlisting>
239 <section xml:id="sec-settings-attrs-options">
240 <title>Option declarations for attributes</title>
241 <para>
242 Some <literal>settings</literal> attributes may deserve some
243 extra care. They may need a different type, default or merging
244 behavior, or they are essential options that should show their
245 documentation in the manual. This can be done using
246 <xref linkend="sec-freeform-modules" />.
247 </para>
248 <para>
249 We extend above example using freeform modules to declare an
250 option for the port, which will enforce it to be a valid integer
251 and make it show up in the manual.
252 </para>
253 <anchor xml:id="ex-settings-typed-attrs" />
254 <para>
255 <emphasis role="strong">Example: Declaring a type-checked
256 <literal>settings</literal> attribute</emphasis>
257 </para>
258 <programlisting language="bash">
259settings = lib.mkOption {
260 type = lib.types.submodule {
261
262 freeformType = settingsFormat.type;
263
264 # Declare an option for the port such that the type is checked and this option
265 # is shown in the manual.
266 options.port = lib.mkOption {
267 type = lib.types.port;
268 default = 8080;
269 description = ''
270 Which port this service should listen on.
271 '';
272 };
273
274 };
275 default = {};
276 description = ''
277 Configuration for Foo, see
278 <link xlink:href="https://example.com/docs/foo"/>
279 for supported values.
280 '';
281};
282</programlisting>
283 </section>
284 </section>
285</section>