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.javaProperties</literal> {
59 <emphasis><literal>comment</literal></emphasis> ?
60 <literal>"Generated with Nix"</literal> }
61 </term>
62 <listitem>
63 <para>
64 A function taking an attribute set with values
65 </para>
66 <variablelist>
67 <varlistentry>
68 <term>
69 <literal>comment</literal>
70 </term>
71 <listitem>
72 <para>
73 A string to put at the start of the file in a comment.
74 It can have multiple lines.
75 </para>
76 </listitem>
77 </varlistentry>
78 </variablelist>
79 <para>
80 It returns the <literal>type</literal>:
81 <literal>attrsOf str</literal> and a function
82 <literal>generate</literal> to build a Java
83 <literal>.properties</literal> file, taking care of the
84 correct escaping, etc.
85 </para>
86 </listitem>
87 </varlistentry>
88 <varlistentry>
89 <term>
90 <literal>pkgs.formats.json</literal> { }
91 </term>
92 <listitem>
93 <para>
94 A function taking an empty attribute set (for future
95 extensibility) and returning a set with JSON-specific
96 attributes <literal>type</literal> and
97 <literal>generate</literal> as specified
98 <link linkend="pkgs-formats-result">below</link>.
99 </para>
100 </listitem>
101 </varlistentry>
102 <varlistentry>
103 <term>
104 <literal>pkgs.formats.yaml</literal> { }
105 </term>
106 <listitem>
107 <para>
108 A function taking an empty attribute set (for future
109 extensibility) and returning a set with YAML-specific
110 attributes <literal>type</literal> and
111 <literal>generate</literal> as specified
112 <link linkend="pkgs-formats-result">below</link>.
113 </para>
114 </listitem>
115 </varlistentry>
116 <varlistentry>
117 <term>
118 <literal>pkgs.formats.ini</literal> {
119 <emphasis><literal>listsAsDuplicateKeys</literal></emphasis> ?
120 false, <emphasis><literal>listToValue</literal></emphasis> ?
121 null, ... }
122 </term>
123 <listitem>
124 <para>
125 A function taking an attribute set with values
126 </para>
127 <variablelist>
128 <varlistentry>
129 <term>
130 <literal>listsAsDuplicateKeys</literal>
131 </term>
132 <listitem>
133 <para>
134 A boolean for controlling whether list values can be
135 used to represent duplicate INI keys
136 </para>
137 </listitem>
138 </varlistentry>
139 <varlistentry>
140 <term>
141 <literal>listToValue</literal>
142 </term>
143 <listitem>
144 <para>
145 A function for turning a list of values into a single
146 value.
147 </para>
148 </listitem>
149 </varlistentry>
150 </variablelist>
151 <para>
152 It returns a set with INI-specific attributes
153 <literal>type</literal> and <literal>generate</literal> as
154 specified <link linkend="pkgs-formats-result">below</link>.
155 </para>
156 </listitem>
157 </varlistentry>
158 <varlistentry>
159 <term>
160 <literal>pkgs.formats.toml</literal> { }
161 </term>
162 <listitem>
163 <para>
164 A function taking an empty attribute set (for future
165 extensibility) and returning a set with TOML-specific
166 attributes <literal>type</literal> and
167 <literal>generate</literal> as specified
168 <link linkend="pkgs-formats-result">below</link>.
169 </para>
170 </listitem>
171 </varlistentry>
172 <varlistentry>
173 <term>
174 <literal>pkgs.formats.elixirConf { elixir ? pkgs.elixir }</literal>
175 </term>
176 <listitem>
177 <para>
178 A function taking an attribute set with values
179 </para>
180 <variablelist>
181 <varlistentry>
182 <term>
183 <literal>elixir</literal>
184 </term>
185 <listitem>
186 <para>
187 The Elixir package which will be used to format the
188 generated output
189 </para>
190 </listitem>
191 </varlistentry>
192 </variablelist>
193 <para>
194 It returns a set with Elixir-Config-specific attributes
195 <literal>type</literal>, <literal>lib</literal>, and
196 <literal>generate</literal> as specified
197 <link linkend="pkgs-formats-result">below</link>.
198 </para>
199 <para>
200 The <literal>lib</literal> attribute contains functions to
201 be used in settings, for generating special Elixir values:
202 </para>
203 <variablelist>
204 <varlistentry>
205 <term>
206 <literal>mkRaw elixirCode</literal>
207 </term>
208 <listitem>
209 <para>
210 Outputs the given string as raw Elixir code
211 </para>
212 </listitem>
213 </varlistentry>
214 <varlistentry>
215 <term>
216 <literal>mkGetEnv { envVariable, fallback ? null }</literal>
217 </term>
218 <listitem>
219 <para>
220 Makes the configuration fetch an environment variable
221 at runtime
222 </para>
223 </listitem>
224 </varlistentry>
225 <varlistentry>
226 <term>
227 <literal>mkAtom atom</literal>
228 </term>
229 <listitem>
230 <para>
231 Outputs the given string as an Elixir atom, instead of
232 the default Elixir binary string. Note: lowercase
233 atoms still needs to be prefixed with
234 <literal>:</literal>
235 </para>
236 </listitem>
237 </varlistentry>
238 <varlistentry>
239 <term>
240 <literal>mkTuple array</literal>
241 </term>
242 <listitem>
243 <para>
244 Outputs the given array as an Elixir tuple, instead of
245 the default Elixir list
246 </para>
247 </listitem>
248 </varlistentry>
249 <varlistentry>
250 <term>
251 <literal>mkMap attrset</literal>
252 </term>
253 <listitem>
254 <para>
255 Outputs the given attribute set as an Elixir map,
256 instead of the default Elixir keyword list
257 </para>
258 </listitem>
259 </varlistentry>
260 </variablelist>
261 </listitem>
262 </varlistentry>
263 </variablelist>
264 <para xml:id="pkgs-formats-result">
265 These functions all return an attribute set with these values:
266 </para>
267 <variablelist>
268 <varlistentry>
269 <term>
270 <literal>type</literal>
271 </term>
272 <listitem>
273 <para>
274 A module system type representing a value of the format
275 </para>
276 </listitem>
277 </varlistentry>
278 <varlistentry>
279 <term>
280 <literal>lib</literal>
281 </term>
282 <listitem>
283 <para>
284 Utility functions for convenience, or special interactions
285 with the format. This attribute is optional. It may contain
286 inside a <literal>types</literal> attribute containing types
287 specific to this format.
288 </para>
289 </listitem>
290 </varlistentry>
291 <varlistentry>
292 <term>
293 <literal>generate</literal>
294 <emphasis><literal>filename jsonValue</literal></emphasis>
295 </term>
296 <listitem>
297 <para>
298 A function that can render a value of the format to a file.
299 Returns a file path.
300 </para>
301 <note>
302 <para>
303 This function puts the value contents in the Nix store. So
304 this should be avoided for secrets.
305 </para>
306 </note>
307 </listitem>
308 </varlistentry>
309 </variablelist>
310 <anchor xml:id="ex-settings-nix-representable" />
311 <para>
312 <emphasis role="strong">Example: Module with conventional
313 <literal>settings</literal> option</emphasis>
314 </para>
315 <para>
316 The following shows a module for an example program that uses a
317 JSON configuration file. It demonstrates how above values can be
318 used, along with some other related best practices. See the
319 comments for explanations.
320 </para>
321 <programlisting language="bash">
322{ options, config, lib, pkgs, ... }:
323let
324 cfg = config.services.foo;
325 # Define the settings format used for this program
326 settingsFormat = pkgs.formats.json {};
327in {
328
329 options.services.foo = {
330 enable = lib.mkEnableOption "foo service";
331
332 settings = lib.mkOption {
333 # Setting this type allows for correct merging behavior
334 type = settingsFormat.type;
335 default = {};
336 description = ''
337 Configuration for foo, see
338 <link xlink:href="https://example.com/docs/foo"/>
339 for supported settings.
340 '';
341 };
342 };
343
344 config = lib.mkIf cfg.enable {
345 # We can assign some default settings here to make the service work by just
346 # enabling it. We use `mkDefault` for values that can be changed without
347 # problems
348 services.foo.settings = {
349 # Fails at runtime without any value set
350 log_level = lib.mkDefault "WARN";
351
352 # We assume systemd's `StateDirectory` is used, so we require this value,
353 # therefore no mkDefault
354 data_path = "/var/lib/foo";
355
356 # Since we use this to create a user we need to know the default value at
357 # eval time
358 user = lib.mkDefault "foo";
359 };
360
361 environment.etc."foo.json".source =
362 # The formats generator function takes a filename and the Nix value
363 # representing the format value and produces a filepath with that value
364 # rendered in the format
365 settingsFormat.generate "foo-config.json" cfg.settings;
366
367 # We know that the `user` attribute exists because we set a default value
368 # for it above, allowing us to use it without worries here
369 users.users.${cfg.settings.user} = { isSystemUser = true; };
370
371 # ...
372 };
373}
374</programlisting>
375 <section xml:id="sec-settings-attrs-options">
376 <title>Option declarations for attributes</title>
377 <para>
378 Some <literal>settings</literal> attributes may deserve some
379 extra care. They may need a different type, default or merging
380 behavior, or they are essential options that should show their
381 documentation in the manual. This can be done using
382 <xref linkend="sec-freeform-modules" />.
383 </para>
384 <para>
385 We extend above example using freeform modules to declare an
386 option for the port, which will enforce it to be a valid integer
387 and make it show up in the manual.
388 </para>
389 <anchor xml:id="ex-settings-typed-attrs" />
390 <para>
391 <emphasis role="strong">Example: Declaring a type-checked
392 <literal>settings</literal> attribute</emphasis>
393 </para>
394 <programlisting language="bash">
395settings = lib.mkOption {
396 type = lib.types.submodule {
397
398 freeformType = settingsFormat.type;
399
400 # Declare an option for the port such that the type is checked and this option
401 # is shown in the manual.
402 options.port = lib.mkOption {
403 type = lib.types.port;
404 default = 8080;
405 description = ''
406 Which port this service should listen on.
407 '';
408 };
409
410 };
411 default = {};
412 description = ''
413 Configuration for Foo, see
414 <link xlink:href="https://example.com/docs/foo"/>
415 for supported values.
416 '';
417};
418</programlisting>
419 </section>
420 </section>
421</section>