biglybt: 3.5.0.0 -> 3.6.0.0
[NixPkgs.git] / nixos / doc / manual / development / writing-modules.chapter.md
blob67a5cc23a6aa5df75d5d900132bb830d70b14749
1 # Writing NixOS Modules {#sec-writing-modules}
3 NixOS has a modular system for declarative configuration. This system
4 combines multiple *modules* to produce the full system configuration.
5 One of the modules that constitute the configuration is
6 `/etc/nixos/configuration.nix`. Most of the others live in the
7 [`nixos/modules`](https://github.com/NixOS/nixpkgs/tree/master/nixos/modules)
8 subdirectory of the Nixpkgs tree.
10 Each NixOS module is a file that handles one logical aspect of the
11 configuration, such as a specific kind of hardware, a service, or
12 network settings. A module configuration does not have to handle
13 everything from scratch; it can use the functionality provided by other
14 modules for its implementation. Thus a module can *declare* options that
15 can be used by other modules, and conversely can *define* options
16 provided by other modules in its own implementation. For example, the
17 module
18 [`pam.nix`](https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/security/pam.nix)
19 declares the option `security.pam.services` that allows other modules (e.g.
20 [`sshd.nix`](https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/services/networking/ssh/sshd.nix))
21 to define PAM services; and it defines the option `environment.etc` (declared by
22 [`etc.nix`](https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/system/etc/etc.nix))
23 to cause files to be created in `/etc/pam.d`.
25 In [](#sec-configuration-syntax), we saw the following structure of
26 NixOS modules:
28 ```nix
29 { config, pkgs, ... }:
31 { # option definitions
33 ```
35 This is actually an *abbreviated* form of module that only defines
36 options, but does not declare any. The structure of full NixOS modules
37 is shown in [Example: Structure of NixOS Modules](#ex-module-syntax).
39 ::: {#ex-module-syntax .example}
40 ### Structure of NixOS Modules
41 ```nix
42 { config, pkgs, ... }:
45   imports =
46     [ # paths of other modules
47     ];
49   options = {
50     # option declarations
51   };
53   config = {
54     # option definitions
55   };
57 ```
58 :::
60 The meaning of each part is as follows.
62 -   The first line makes the current Nix expression a function. The variable
63     `pkgs` contains Nixpkgs (by default, it takes the `nixpkgs` entry of
64     `NIX_PATH`, see the [Nix manual](https://nixos.org/manual/nix/stable/#sec-common-env)
65     for further details), while `config` contains the full system
66     configuration. This line can be omitted if there is no reference to
67     `pkgs` and `config` inside the module.
69 -   This `imports` list enumerates the paths to other NixOS modules that
70     should be included in the evaluation of the system configuration. A
71     default set of modules is defined in the file `modules/module-list.nix`.
72     These don't need to be added in the import list.
74 -   The attribute `options` is a nested set of *option declarations*
75     (described below).
77 -   The attribute `config` is a nested set of *option definitions* (also
78     described below).
80 [Example: NixOS Module for the "locate" Service](#locate-example)
81 shows a module that handles the regular update of the "locate" database,
82 an index of all files in the file system. This module declares two
83 options that can be defined by other modules (typically the user's
84 `configuration.nix`): `services.locate.enable` (whether the database should
85 be updated) and `services.locate.interval` (when the update should be done).
86 It implements its functionality by defining two options declared by other
87 modules: `systemd.services` (the set of all systemd services) and
88 `systemd.timers` (the list of commands to be executed periodically by
89 `systemd`).
91 Care must be taken when writing systemd services using `Exec*` directives. By
92 default systemd performs substitution on `%<char>` specifiers in these
93 directives, expands environment variables from `$FOO` and `${FOO}`, splits
94 arguments on whitespace, and splits commands on `;`. All of these must be escaped
95 to avoid unexpected substitution or splitting when interpolating into an `Exec*`
96 directive, e.g. when using an `extraArgs` option to pass additional arguments to
97 the service. The functions `utils.escapeSystemdExecArg` and
98 `utils.escapeSystemdExecArgs` are provided for this, see [Example: Escaping in
99 Exec directives](#exec-escaping-example) for an example. When using these
100 functions system environment substitution should *not* be disabled explicitly.
102 ::: {#locate-example .example}
103 ### NixOS Module for the "locate" Service
104 ```nix
105 { config, lib, pkgs, ... }:
108   inherit (lib) concatStringsSep mkIf mkOption optionalString types;
109   cfg = config.services.locate;
110 in {
111   options.services.locate = {
112     enable = mkOption {
113       type = types.bool;
114       default = false;
115       description = ''
116         If enabled, NixOS will periodically update the database of
117         files used by the locate command.
118       '';
119     };
121     interval = mkOption {
122       type = types.str;
123       default = "02:15";
124       example = "hourly";
125       description = ''
126         Update the locate database at this interval. Updates by
127         default at 2:15 AM every day.
129         The format is described in
130         systemd.time(7).
131       '';
132     };
134     # Other options omitted for documentation
135   };
137   config = {
138     systemd.services.update-locatedb =
139       { description = "Update Locate Database";
140         path  = [ pkgs.su ];
141         script =
142           ''
143             mkdir -m 0755 -p $(dirname ${toString cfg.output})
144             exec updatedb \
145               --localuser=${cfg.localuser} \
146               ${optionalString (!cfg.includeStore) "--prunepaths='/nix/store'"} \
147               --output=${toString cfg.output} ${concatStringsSep " " cfg.extraFlags}
148           '';
149       };
151     systemd.timers.update-locatedb = mkIf cfg.enable
152       { description = "Update timer for locate database";
153         partOf      = [ "update-locatedb.service" ];
154         wantedBy    = [ "timers.target" ];
155         timerConfig.OnCalendar = cfg.interval;
156       };
157   };
162 ::: {#exec-escaping-example .example}
163 ### Escaping in Exec directives
164 ```nix
165 { config, pkgs, utils, ... }:
168   cfg = config.services.echo;
169   echoAll = pkgs.writeScript "echo-all" ''
170     #! ${pkgs.runtimeShell}
171     for s in "$@"; do
172       printf '%s\n' "$s"
173     done
174   '';
175   args = [ "a%Nything" "lang=\${LANG}" ";" "/bin/sh -c date" ];
176 in {
177   systemd.services.echo =
178     { description = "Echo to the journal";
179       wantedBy = [ "multi-user.target" ];
180       serviceConfig.Type = "oneshot";
181       serviceConfig.ExecStart = ''
182         ${echoAll} ${utils.escapeSystemdExecArgs args}
183       '';
184     };
189 ```{=include=} sections
190 option-declarations.section.md
191 option-types.section.md
192 option-def.section.md
193 assertions.section.md
194 meta-attributes.section.md
195 importing-modules.section.md
196 replace-modules.section.md
197 freeform-modules.section.md
198 settings-options.section.md