1# Options for Program Settings {#sec-settings-options}
2
3Many programs have configuration files where program-specific settings
4can be declared. File formats can be separated into two categories:
5
6- Nix-representable ones: These can trivially be mapped to a subset of
7 Nix syntax. E.g. JSON is an example, since its values like
8 `{"foo":{"bar":10}}` can be mapped directly to Nix:
9 `{ foo = { bar = 10; }; }`. Other examples are INI, YAML and TOML.
10 The following section explains the convention for these settings.
11
12- Non-nix-representable ones: These can't be trivially mapped to a
13 subset of Nix syntax. Most generic programming languages are in this
14 group, e.g. bash, since the statement `if true; then echo hi; fi`
15 doesn't have a trivial representation in Nix.
16
17 Currently there are no fixed conventions for these, but it is common
18 to have a `configFile` option for setting the configuration file
19 path directly. The default value of `configFile` can be an
20 auto-generated file, with convenient options for controlling the
21 contents. For example an option of type `attrsOf str` can be used
22 for representing environment variables which generates a section
23 like `export FOO="foo"`. Often it can also be useful to also include
24 an `extraConfig` option of type `lines` to allow arbitrary text
25 after the autogenerated part of the file.
26
27## Nix-representable Formats (JSON, YAML, TOML, INI, ...) {#sec-settings-nix-representable}
28
29By convention, formats like this are handled with a generic `settings`
30option, representing the full program configuration as a Nix value. The
31type of this option should represent the format. The most common formats
32have a predefined type and string generator already declared under
33`pkgs.formats`:
34
35`pkgs.formats.javaProperties` { *`comment`* ? `"Generated with Nix"` }
36
37: A function taking an attribute set with values
38
39 `comment`
40
41 : A string to put at the start of the
42 file in a comment. It can have multiple
43 lines.
44
45 It returns the `type`: `attrsOf str` and a function
46 `generate` to build a Java `.properties` file, taking
47 care of the correct escaping, etc.
48
49`pkgs.formats.hocon` { *`generator`* ? `<derivation>`, *`validator`* ? `<derivation>`, *`doCheck`* ? true }
50
51: A function taking an attribute set with values
52
53 `generator`
54
55 : A derivation used for converting the JSON output
56 from the nix settings into HOCON. This might be
57 useful if your HOCON variant is slightly different
58 from the java-based one, or for testing purposes.
59
60 `validator`
61
62 : A derivation used for verifying that the HOCON
63 output is correct and parsable. This might be
64 useful if your HOCON variant is slightly different
65 from the java-based one, or for testing purposes.
66
67 `doCheck`
68
69 : Whether to enable/disable the validator check.
70
71 It returns an attrset with a `type`, `generate` function,
72 and a `lib` attset, as specified [below](#pkgs-formats-result).
73 Some of the lib functions will be best understood if you have
74 read the reference specification. You can find this
75 specification here:
76
77 <https://github.com/lightbend/config/blob/main/HOCON.md>
78
79 Inside of `lib`, you will find these functions
80
81 `mkInclude`
82
83 : This is used together with a specially named
84 attribute `includes`, to include other HOCON
85 sources into the document.
86
87 The function has a shorthand variant where it
88 is up to the HOCON parser to figure out what type
89 of include is being used. The include will default
90 to being non-required. If you want to be more
91 explicit about the details of the include, you can
92 provide an attrset with following arguments
93
94 `required`
95
96 : Whether the parser should fail upon failure
97 to include the document
98
99 `type`
100
101 : Type of the source of the included document.
102 Valid values are `file`, `url` and `classpath`.
103 See upstream documentation for the semantics
104 behind each value
105
106 `value`
107
108 : The URI/path/classpath pointing to the source of
109 the document to be included.
110
111 `Example usage:`
112
113 ```nix
114 let
115 format = pkgs.formats.hocon { };
116 hocon_file = pkgs.writeText "to_include.hocon" ''
117 a = 1;
118 '';
119 in {
120 some.nested.hocon.attrset = {
121 _includes = [
122 (format.lib.mkInclude hocon_file)
123 (format.lib.mkInclude "https://example.com/to_include.hocon")
124 (format.lib.mkInclude {
125 required = true;
126 type = "file";
127 value = include_file;
128 })
129 ];
130 ...
131 };
132 }
133 ```
134
135 `mkAppend`
136
137 : This is used to invoke the `+=` operator.
138 This can be useful if you need to add something
139 to a list that is included from outside of nix.
140 See upstream documentation for the semantics
141 behind the `+=` operation.
142
143 `Example usage:`
144
145 ```nix
146 let
147 format = pkgs.formats.hocon { };
148 hocon_file = pkgs.writeText "to_include.hocon" ''
149 a = [ 1 ];
150 b = [ 2 ];
151 '';
152 in {
153 _includes = [
154 (format.lib.mkInclude hocon_file)
155 ];
156
157 c = 3;
158 a = format.lib.mkAppend 3;
159 b = format.lib.mkAppend (format.lib.mkSubstitution "c");
160 }
161 ```
162
163 `mkSubstitution`
164
165 : This is used to make HOCON substitutions.
166 Similarly to `mkInclude`, this function has
167 a shorthand variant where you just give it
168 the string with the substitution value.
169 The substitution is not optional by default.
170 Alternatively, you can provide an attrset
171 with more options
172
173 `optional`
174
175 : Whether the parser should fail upon
176 failure to fetch the substitution value.
177
178 `value`
179
180 : The name of the variable to use for
181 substitution.
182
183 See upstream documentation for semantics
184 behind the substitution functionality.
185
186 `Example usage:`
187
188 ```nix
189 let
190 format = pkgs.formats.hocon { };
191 in {
192 a = 1;
193 b = format.lib.mkSubstitution "a";
194 c = format.lib.mkSubstitution "SOME_ENVVAR";
195 d = format.lib.mkSubstitution {
196 value = "SOME_OPTIONAL_ENVVAR";
197 optional = true;
198 };
199 }
200 ```
201
202 `Implementation notes:`
203
204 - classpath includes are not implemented in pyhocon,
205 which is used for validating the HOCON output. This
206 means that if you are using classpath includes,
207 you will want to either use an alternative validator
208 or set `doCheck = false` in the format options.
209
210`pkgs.formats.libconfig` { *`generator`* ? `<derivation>`, *`validator`* ? `<derivation>` }
211
212: A function taking an attribute set with values
213
214 `generator`
215
216 : A derivation used for converting the JSON output
217 from the nix settings into libconfig. This might be
218 useful if your libconfig variant is slightly different
219 from the original one, or for testing purposes.
220
221 `validator`
222
223 : A derivation used for verifying that the libconfig
224 output is correct and parsable. This might be
225 useful if your libconfig variant is slightly different
226 from the original one, or for testing purposes.
227
228 It returns an attrset with a `type`, `generate` function,
229 and a `lib` attset, as specified [below](#pkgs-formats-result).
230 Some of the lib functions will be best understood if you have
231 read the reference specification. You can find this
232 specification here:
233
234 <https://hyperrealm.github.io/libconfig/libconfig_manual.html#Configuration-Files>
235
236 Inside of `lib`, you will find these functions
237
238 `mkHex`, `mkOctal`, `mkFloat`
239
240 : Use these to specify numbers in other formats.
241
242 `Example usage:`
243
244 ```nix
245 let
246 format = pkgs.formats.libconfig { };
247 in {
248 myHexValue = format.lib.mkHex "0x1FC3";
249 myOctalValue = format.lib.mkOctal "0027";
250 myFloatValue = format.lib.mkFloat "1.2E-3";
251 }
252 ```
253
254 `mkArray`, `mkList`
255
256 : Use these to differentiate between whether
257 a nix list should be considered as a libconfig
258 array or a libconfig list. See the upstream
259 documentation for the semantics behind these types.
260
261 `Example usage:`
262
263 ```nix
264 let
265 format = pkgs.formats.libconfig { };
266 in {
267 myList = format.lib.mkList [ "foo" 1 true ];
268 myArray = format.lib.mkArray [ 1 2 3 ];
269 }
270 ```
271
272 `Implementation notes:`
273
274 - Since libconfig does not allow setting names to start with an underscore,
275 this is used as a prefix for both special types and include directives.
276
277 - The difference between 32bit and 64bit values became optional in libconfig
278 1.5, so we assume 64bit values for all numbers.
279
280`pkgs.formats.json` { }
281
282: A function taking an empty attribute set (for future extensibility)
283 and returning a set with JSON-specific attributes `type` and
284 `generate` as specified [below](#pkgs-formats-result).
285
286`pkgs.formats.yaml` { }
287
288: A function taking an empty attribute set (for future extensibility)
289 and returning a set with YAML-specific attributes `type` and
290 `generate` as specified [below](#pkgs-formats-result).
291
292`pkgs.formats.ini` { *`listsAsDuplicateKeys`* ? false, *`listToValue`* ? null, \.\.\. }
293
294: A function taking an attribute set with values
295
296 `listsAsDuplicateKeys`
297
298 : A boolean for controlling whether list values can be used to
299 represent duplicate INI keys
300
301 `listToValue`
302
303 : A function for turning a list of values into a single value.
304
305 It returns a set with INI-specific attributes `type` and `generate`
306 as specified [below](#pkgs-formats-result).
307 The type of the input is an *attrset* of sections; key-value pairs where
308 the key is the section name and the value is the corresponding content
309 which is also an *attrset* of key-value pairs for the actual key-value
310 mappings of the INI format.
311 The values of the INI atoms are subject to the above parameters (e.g. lists
312 may be transformed into multiple key-value pairs depending on
313 `listToValue`).
314
315 The attribute `lib.type.atom` contains the used INI atom.
316
317`pkgs.formats.iniWithGlobalSection` { *`listsAsDuplicateKeys`* ? false, *`listToValue`* ? null, \.\.\. }
318
319: A function taking an attribute set with values
320
321 `listsAsDuplicateKeys`
322
323 : A boolean for controlling whether list values can be used to
324 represent duplicate INI keys
325
326 `listToValue`
327
328 : A function for turning a list of values into a single value.
329
330 It returns a set with INI-specific attributes `type` and `generate`
331 as specified [below](#pkgs-formats-result).
332 The type of the input is an *attrset* of the structure
333 `{ sections = {}; globalSection = {}; }` where *sections* are several
334 sections as with *pkgs.formats.ini* and *globalSection* being just a single
335 attrset of key-value pairs for a single section, the global section which
336 precedes the section definitions.
337
338 The attribute `lib.type.atom` contains the used INI atom.
339
340`pkgs.formats.toml` { }
341
342: A function taking an empty attribute set (for future extensibility)
343 and returning a set with TOML-specific attributes `type` and
344 `generate` as specified [below](#pkgs-formats-result).
345
346`pkgs.formats.xml` { format ? "badgerfish", withHeader ? true}
347
348: A function taking an attribute set with values
349 and returning a set with XML-specific attributes `type` and
350 `generate` as specified [below](#pkgs-formats-result).
351
352 `format`
353
354 : Input format. Because XML can not be translated one-to-one, we have to use intermediate formats. Possible values:
355 - `"badgerfish"`: Uses [badgerfish](http://www.sklar.com/badgerfish/) conversion.
356
357 `withHeader`
358
359 : Outputs the xml with header.
360
361`pkgs.formats.cdn` { }
362
363: A function taking an empty attribute set (for future extensibility)
364 and returning a set with [CDN](https://github.com/dzikoysk/cdn)-specific
365 attributes `type` and `generate` as specified [below](#pkgs-formats-result).
366
367`pkgs.formats.elixirConf { elixir ? pkgs.elixir }`
368
369: A function taking an attribute set with values
370
371 `elixir`
372
373 : The Elixir package which will be used to format the generated output
374
375 It returns a set with Elixir-Config-specific attributes `type`, `lib`, and
376 `generate` as specified [below](#pkgs-formats-result).
377
378 The `lib` attribute contains functions to be used in settings, for
379 generating special Elixir values:
380
381 `mkRaw elixirCode`
382
383 : Outputs the given string as raw Elixir code
384
385 `mkGetEnv { envVariable, fallback ? null }`
386
387 : Makes the configuration fetch an environment variable at runtime
388
389 `mkAtom atom`
390
391 : Outputs the given string as an Elixir atom, instead of the default
392 Elixir binary string. Note: lowercase atoms still needs to be prefixed
393 with `:`
394
395 `mkTuple array`
396
397 : Outputs the given array as an Elixir tuple, instead of the default
398 Elixir list
399
400 `mkMap attrset`
401
402 : Outputs the given attribute set as an Elixir map, instead of the
403 default Elixir keyword list
404
405`pkgs.formats.lua { asBindings ? false, multiline ? true, columnWidth ? 100, indentWidth ? 2, indentUsingTabs ? false }`
406
407: A function taking an attribute set with values
408
409 `asBindings` (default `false`)
410
411 : Whether to treat attributes as variable bindings
412
413 `multiline` (default `true`)
414
415 : Whether to produce a multiline output. The output may still wrap across
416 multiple lines if it would otherwise exceed `columnWidth`.
417
418 `columnWidth` (default `100`)
419
420 : The column width to use to attempt to wrap lines.
421
422 `indentWidth` (default `2`)
423
424 : The width of a single indentation level.
425
426 `indentUsingTabs` (default `false`)
427
428 : Whether the indentation should use tabs instead of spaces.
429
430`pkgs.formats.php { finalVariable }` []{#pkgs-formats-php}
431
432: A function taking an attribute set with values
433
434 `finalVariable`
435
436 : The variable that will store generated expression (usually `config`). If set to `null`, generated expression will contain `return`.
437
438 It returns a set with PHP-Config-specific attributes `type`, `lib`, and
439 `generate` as specified [below](#pkgs-formats-result).
440
441 The `lib` attribute contains functions to be used in settings, for
442 generating special PHP values:
443
444 `mkRaw phpCode`
445
446 : Outputs the given string as raw PHP code
447
448 `mkMixedArray list set`
449
450 : Creates PHP array that contains both indexed and associative values. For example, `lib.mkMixedArray [ "hello" "world" ] { "nix" = "is-great"; }` returns `['hello', 'world', 'nix' => 'is-great']`
451
452[]{#pkgs-formats-result}
453These functions all return an attribute set with these values:
454
455`type`
456
457: A module system type representing a value of the format
458
459`lib`
460
461: Utility functions for convenience, or special interactions with the format.
462 This attribute is optional. It may contain inside a `types` attribute
463 containing types specific to this format.
464
465`generate` *`filename jsonValue`*
466
467: A function that can render a value of the format to a file. Returns
468 a file path.
469
470 ::: {.note}
471 This function puts the value contents in the Nix store. So this
472 should be avoided for secrets.
473 :::
474
475::: {#ex-settings-nix-representable .example}
476### Module with conventional `settings` option
477
478The following shows a module for an example program that uses a JSON
479configuration file. It demonstrates how above values can be used, along
480with some other related best practices. See the comments for
481explanations.
482
483```nix
484{ options, config, lib, pkgs, ... }:
485let
486 cfg = config.services.foo;
487 # Define the settings format used for this program
488 settingsFormat = pkgs.formats.json {};
489in {
490
491 options.services.foo = {
492 enable = lib.mkEnableOption "foo service";
493
494 settings = lib.mkOption {
495 # Setting this type allows for correct merging behavior
496 type = settingsFormat.type;
497 default = {};
498 description = ''
499 Configuration for foo, see
500 <link xlink:href="https://example.com/docs/foo"/>
501 for supported settings.
502 '';
503 };
504 };
505
506 config = lib.mkIf cfg.enable {
507 # We can assign some default settings here to make the service work by just
508 # enabling it. We use `mkDefault` for values that can be changed without
509 # problems
510 services.foo.settings = {
511 # Fails at runtime without any value set
512 log_level = lib.mkDefault "WARN";
513
514 # We assume systemd's `StateDirectory` is used, so we require this value,
515 # therefore no mkDefault
516 data_path = "/var/lib/foo";
517
518 # Since we use this to create a user we need to know the default value at
519 # eval time
520 user = lib.mkDefault "foo";
521 };
522
523 environment.etc."foo.json".source =
524 # The formats generator function takes a filename and the Nix value
525 # representing the format value and produces a filepath with that value
526 # rendered in the format
527 settingsFormat.generate "foo-config.json" cfg.settings;
528
529 # We know that the `user` attribute exists because we set a default value
530 # for it above, allowing us to use it without worries here
531 users.users.${cfg.settings.user} = { isSystemUser = true; };
532
533 # ...
534 };
535}
536```
537:::
538
539### Option declarations for attributes {#sec-settings-attrs-options}
540
541Some `settings` attributes may deserve some extra care. They may need a
542different type, default or merging behavior, or they are essential
543options that should show their documentation in the manual. This can be
544done using [](#sec-freeform-modules).
545
546We extend above example using freeform modules to declare an option for
547the port, which will enforce it to be a valid integer and make it show
548up in the manual.
549
550::: {#ex-settings-typed-attrs .example}
551### Declaring a type-checked `settings` attribute
552```nix
553{
554 settings = lib.mkOption {
555 type = lib.types.submodule {
556
557 freeformType = settingsFormat.type;
558
559 # Declare an option for the port such that the type is checked and this option
560 # is shown in the manual.
561 options.port = lib.mkOption {
562 type = lib.types.port;
563 default = 8080;
564 description = ''
565 Which port this service should listen on.
566 '';
567 };
568
569 };
570 default = {};
571 description = ''
572 Configuration for Foo, see
573 <link xlink:href="https://example.com/docs/foo"/>
574 for supported values.
575 '';
576 };
577}
578```
579:::