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
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
29 { config, pkgs, ... }:
31 { # option definitions
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
42 { config, pkgs, ... }:
46 [ # paths of other modules
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*
77 - The attribute `config` is a nested set of *option definitions* (also
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
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
105 { config, lib, pkgs, ... }:
108 inherit (lib) concatStringsSep mkIf mkOption optionalString types;
109 cfg = config.services.locate;
111 options.services.locate = {
116 If enabled, NixOS will periodically update the database of
117 files used by the locate command.
121 interval = mkOption {
126 Update the locate database at this interval. Updates by
127 default at 2:15 AM every day.
129 The format is described in
134 # Other options omitted for documentation
138 systemd.services.update-locatedb =
139 { description = "Update Locate Database";
143 mkdir -m 0755 -p $(dirname ${toString cfg.output})
145 --localuser=${cfg.localuser} \
146 ${optionalString (!cfg.includeStore) "--prunepaths='/nix/store'"} \
147 --output=${toString cfg.output} ${concatStringsSep " " cfg.extraFlags}
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;
162 ::: {#exec-escaping-example .example}
163 ### Escaping in Exec directives
165 { config, pkgs, utils, ... }:
168 cfg = config.services.echo;
169 echoAll = pkgs.writeScript "echo-all" ''
170 #! ${pkgs.runtimeShell}
175 args = [ "a%Nything" "lang=\${LANG}" ";" "/bin/sh -c date" ];
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}
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