1<chapter xmlns="http://docbook.org/ns/docbook"
2 xmlns:xlink="http://www.w3.org/1999/xlink"
3 xmlns:xi="http://www.w3.org/2001/XInclude"
4 version="5.0"
5 xml:id="sec-writing-modules">
6
7<title>Writing NixOS Modules</title>
8
9<para>NixOS has a modular system for declarative configuration. This
10system combines multiple <emphasis>modules</emphasis> to produce the
11full system configuration. One of the modules that constitute the
12configuration is <filename>/etc/nixos/configuration.nix</filename>.
13Most of the others live in the <link
14xlink:href="https://github.com/NixOS/nixpkgs/tree/master/nixos/modules"><filename>nixos/modules</filename></link>
15subdirectory of the Nixpkgs tree.</para>
16
17<para>Each NixOS module is a file that handles one logical aspect of
18the configuration, such as a specific kind of hardware, a service, or
19network settings. A module configuration does not have to handle
20everything from scratch; it can use the functionality provided by
21other modules for its implementation. Thus a module can
22<emphasis>declare</emphasis> options that can be used by other
23modules, and conversely can <emphasis>define</emphasis> options
24provided by other modules in its own implementation. For example, the
25module <link
26xlink:href="https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/security/pam.nix"><filename>pam.nix</filename></link>
27declares the option <option>security.pam.services</option> that allows
28other modules (e.g. <link
29xlink:href="https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/services/networking/ssh/sshd.nix"><filename>sshd.nix</filename></link>)
30to define PAM services; and it defines the option
31<option>environment.etc</option> (declared by <link
32xlink:href="https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/system/etc/etc.nix"><filename>etc.nix</filename></link>)
33to cause files to be created in
34<filename>/etc/pam.d</filename>.</para>
35
36<para xml:id="para-module-syn">In <xref
37linkend="sec-configuration-syntax"/>, we saw the following structure
38of NixOS modules:
39
40<programlisting>
41{ config, pkgs, ... }:
42
43{ <replaceable>option definitions</replaceable>
44}
45</programlisting>
46
47This is actually an <emphasis>abbreviated</emphasis> form of module
48that only defines options, but does not declare any. The structure of
49full NixOS modules is shown in <xref linkend='ex-module-syntax' />.</para>
50
51<example xml:id='ex-module-syntax'><title>Structure of NixOS Modules</title>
52<programlisting>
53{ config, pkgs, ... }: <co xml:id='module-syntax-1' />
54
55{
56 imports =
57 [ <replaceable>paths of other modules</replaceable> <co xml:id='module-syntax-2' />
58 ];
59
60 options = {
61 <replaceable>option declarations</replaceable> <co xml:id='module-syntax-3' />
62 };
63
64 config = {
65 <replaceable>option definitions</replaceable> <co xml:id='module-syntax-4' />
66 };
67}</programlisting>
68</example>
69
70<para>The meaning of each part is as follows.
71
72<calloutlist>
73 <callout arearefs='module-syntax-1'>
74 <para>This line makes the current Nix expression a function. The
75 variable <varname>pkgs</varname> contains Nixpkgs, while
76 <varname>config</varname> contains the full system configuration.
77 This line can be omitted if there is no reference to
78 <varname>pkgs</varname> and <varname>config</varname> inside the
79 module.</para>
80 </callout>
81
82 <callout arearefs='module-syntax-2'>
83 <para>This list enumerates the paths to other NixOS modules that
84 should be included in the evaluation of the system configuration.
85 A default set of modules is defined in the file
86 <filename>modules/module-list.nix</filename>. These don't need to
87 be added in the import list.</para>
88 </callout>
89
90 <callout arearefs='module-syntax-3'>
91 <para>The attribute <varname>options</varname> is a nested set of
92 <emphasis>option declarations</emphasis> (described below).</para>
93 </callout>
94
95 <callout arearefs='module-syntax-4'>
96 <para>The attribute <varname>config</varname> is a nested set of
97 <emphasis>option definitions</emphasis> (also described
98 below).</para>
99 </callout>
100</calloutlist>
101
102</para>
103
104<para><xref linkend='locate-example' /> shows a module that handles
105the regular update of the “locate” database, an index of all files in
106the file system. This module declares two options that can be defined
107by other modules (typically the user’s
108<filename>configuration.nix</filename>):
109<option>services.locate.enable</option> (whether the database should
110be updated) and <option>services.locate.period</option> (when the
111update should be done). It implements its functionality by defining
112two options declared by other modules:
113<option>systemd.services</option> (the set of all systemd services)
114and <option>services.cron.systemCronJobs</option> (the list of
115commands to be executed periodically by <command>cron</command>).</para>
116
117<example xml:id='locate-example'><title>NixOS Module for the “locate” Service</title>
118<programlisting>
119{ config, lib, pkgs, ... }:
120
121with lib;
122
123let locatedb = "/var/cache/locatedb"; in
124
125{
126 options = {
127
128 services.locate = {
129
130 enable = mkOption {
131 type = types.bool;
132 default = false;
133 description = ''
134 If enabled, NixOS will periodically update the database of
135 files used by the <command>locate</command> command.
136 '';
137 };
138
139 period = mkOption {
140 type = types.str;
141 default = "15 02 * * *";
142 description = ''
143 This option defines (in the format used by cron) when the
144 locate database is updated. The default is to update at
145 02:15 at night every day.
146 '';
147 };
148
149 };
150
151 };
152
153 config = {
154
155 systemd.services.update-locatedb =
156 { description = "Update Locate Database";
157 path = [ pkgs.su ];
158 script =
159 ''
160 mkdir -m 0755 -p $(dirname ${locatedb})
161 exec updatedb --localuser=nobody --output=${locatedb} --prunepaths='/tmp /var/tmp /run'
162 '';
163 };
164
165 services.cron.systemCronJobs = optional config.services.locate.enable
166 "${config.services.locate.period} root ${config.systemd.package}/bin/systemctl start update-locatedb.service";
167
168 };
169}</programlisting>
170</example>
171
172<xi:include href="option-declarations.xml" />
173<xi:include href="option-def.xml" />
174
175</chapter>