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.json` { }
36
37: A function taking an empty attribute set (for future extensibility)
38 and returning a set with JSON-specific attributes `type` and
39 `generate` as specified [below](#pkgs-formats-result).
40
41`pkgs.formats.yaml` { }
42
43: A function taking an empty attribute set (for future extensibility)
44 and returning a set with YAML-specific attributes `type` and
45 `generate` as specified [below](#pkgs-formats-result).
46
47`pkgs.formats.ini` { *`listsAsDuplicateKeys`* ? false, *`listToValue`* ? null, \... }
48
49: A function taking an attribute set with values
50
51 `listsAsDuplicateKeys`
52
53 : A boolean for controlling whether list values can be used to
54 represent duplicate INI keys
55
56 `listToValue`
57
58 : A function for turning a list of values into a single value.
59
60 It returns a set with INI-specific attributes `type` and `generate`
61 as specified [below](#pkgs-formats-result).
62
63`pkgs.formats.toml` { }
64
65: A function taking an empty attribute set (for future extensibility)
66 and returning a set with TOML-specific attributes `type` and
67 `generate` as specified [below](#pkgs-formats-result).
68
69::: {#pkgs-formats-result}
70These functions all return an attribute set with these values:
71:::
72
73`type`
74
75: A module system type representing a value of the format
76
77`generate` *`filename jsonValue`*
78
79: A function that can render a value of the format to a file. Returns
80 a file path.
81
82 ::: {.note}
83 This function puts the value contents in the Nix store. So this
84 should be avoided for secrets.
85 :::
86
87::: {#ex-settings-nix-representable .example}
88::: {.title}
89**Example: Module with conventional `settings` option**
90:::
91The following shows a module for an example program that uses a JSON
92configuration file. It demonstrates how above values can be used, along
93with some other related best practices. See the comments for
94explanations.
95
96```nix
97{ options, config, lib, pkgs, ... }:
98let
99 cfg = config.services.foo;
100 # Define the settings format used for this program
101 settingsFormat = pkgs.formats.json {};
102in {
103
104 options.services.foo = {
105 enable = lib.mkEnableOption "foo service";
106
107 settings = lib.mkOption {
108 # Setting this type allows for correct merging behavior
109 type = settingsFormat.type;
110 default = {};
111 description = ''
112 Configuration for foo, see
113 <link xlink:href="https://example.com/docs/foo"/>
114 for supported settings.
115 '';
116 };
117 };
118
119 config = lib.mkIf cfg.enable {
120 # We can assign some default settings here to make the service work by just
121 # enabling it. We use `mkDefault` for values that can be changed without
122 # problems
123 services.foo.settings = {
124 # Fails at runtime without any value set
125 log_level = lib.mkDefault "WARN";
126
127 # We assume systemd's `StateDirectory` is used, so we require this value,
128 # therefore no mkDefault
129 data_path = "/var/lib/foo";
130
131 # Since we use this to create a user we need to know the default value at
132 # eval time
133 user = lib.mkDefault "foo";
134 };
135
136 environment.etc."foo.json".source =
137 # The formats generator function takes a filename and the Nix value
138 # representing the format value and produces a filepath with that value
139 # rendered in the format
140 settingsFormat.generate "foo-config.json" cfg.settings;
141
142 # We know that the `user` attribute exists because we set a default value
143 # for it above, allowing us to use it without worries here
144 users.users.${cfg.settings.user} = { isSystemUser = true; };
145
146 # ...
147 };
148}
149```
150:::
151
152### Option declarations for attributes {#sec-settings-attrs-options}
153
154Some `settings` attributes may deserve some extra care. They may need a
155different type, default or merging behavior, or they are essential
156options that should show their documentation in the manual. This can be
157done using [](#sec-freeform-modules).
158
159We extend above example using freeform modules to declare an option for
160the port, which will enforce it to be a valid integer and make it show
161up in the manual.
162
163::: {#ex-settings-typed-attrs .example}
164::: {.title}
165**Example: Declaring a type-checked `settings` attribute**
166:::
167```nix
168settings = lib.mkOption {
169 type = lib.types.submodule {
170
171 freeformType = settingsFormat.type;
172
173 # Declare an option for the port such that the type is checked and this option
174 # is shown in the manual.
175 options.port = lib.mkOption {
176 type = lib.types.port;
177 default = 8080;
178 description = ''
179 Which port this service should listen on.
180 '';
181 };
182
183 };
184 default = {};
185 description = ''
186 Configuration for Foo, see
187 <link xlink:href="https://example.com/docs/foo"/>
188 for supported values.
189 '';
190};
191```
192:::