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