1<section 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-modularity">
6
7<title>Modularity</title>
8
9<para>The NixOS configuration mechanism is modular. If your
10<filename>configuration.nix</filename> becomes too big, you can split
11it into multiple files. Likewise, if you have multiple NixOS
12configurations (e.g. for different computers) with some commonality,
13you can move the common configuration into a shared file.</para>
14
15<para>Modules have exactly the same syntax as
16<filename>configuration.nix</filename>. In fact,
17<filename>configuration.nix</filename> is itself a module. You can
18use other modules by including them from
19<filename>configuration.nix</filename>, e.g.:
20
21<programlisting>
22{ config, pkgs, ... }:
23
24{ imports = [ ./vpn.nix ./kde.nix ];
25 services.httpd.enable = true;
26 environment.systemPackages = [ pkgs.emacs ];
27 <replaceable>...</replaceable>
28}
29</programlisting>
30
31Here, we include two modules from the same directory,
32<filename>vpn.nix</filename> and <filename>kde.nix</filename>. The
33latter might look like this:
34
35<programlisting>
36{ config, pkgs, ... }:
37
38{ services.xserver.enable = true;
39 services.xserver.displayManager.sddm.enable = true;
40 services.xserver.desktopManager.plasma5.enable = true;
41}
42</programlisting>
43
44Note that both <filename>configuration.nix</filename> and
45<filename>kde.nix</filename> define the option
46<option>environment.systemPackages</option>. When multiple modules
47define an option, NixOS will try to <emphasis>merge</emphasis> the
48definitions. In the case of
49<option>environment.systemPackages</option>, that’s easy: the lists of
50packages can simply be concatenated. The value in
51<filename>configuration.nix</filename> is merged last, so for
52list-type options, it will appear at the end of the merged list. If
53you want it to appear first, you can use <varname>mkBefore</varname>:
54
55<programlisting>
56boot.kernelModules = mkBefore [ "kvm-intel" ];
57</programlisting>
58
59This causes the <literal>kvm-intel</literal> kernel module to be
60loaded before any other kernel modules.</para>
61
62<para>For other types of options, a merge may not be possible. For
63instance, if two modules define
64<option>services.httpd.adminAddr</option>,
65<command>nixos-rebuild</command> will give an error:
66
67<screen>
68The unique option `services.httpd.adminAddr' is defined multiple times, in `/etc/nixos/httpd.nix' and `/etc/nixos/configuration.nix'.
69</screen>
70
71When that happens, it’s possible to force one definition take
72precedence over the others:
73
74<programlisting>
75services.httpd.adminAddr = pkgs.lib.mkForce "bob@example.org";
76</programlisting>
77
78</para>
79
80<para>When using multiple modules, you may need to access
81configuration values defined in other modules. This is what the
82<varname>config</varname> function argument is for: it contains the
83complete, merged system configuration. That is,
84<varname>config</varname> is the result of combining the
85configurations returned by every module<footnote><para>If you’re
86wondering how it’s possible that the (indirect)
87<emphasis>result</emphasis> of a function is passed as an
88<emphasis>input</emphasis> to that same function: that’s because Nix
89is a “lazy” language — it only computes values when they are needed.
90This works as long as no individual configuration value depends on
91itself.</para></footnote>. For example, here is a module that adds
92some packages to <option>environment.systemPackages</option> only if
93<option>services.xserver.enable</option> is set to
94<literal>true</literal> somewhere else:
95
96<programlisting>
97{ config, pkgs, ... }:
98
99{ environment.systemPackages =
100 if config.services.xserver.enable then
101 [ pkgs.firefox
102 pkgs.thunderbird
103 ]
104 else
105 [ ];
106}
107</programlisting>
108
109</para>
110
111<para>With multiple modules, it may not be obvious what the final
112value of a configuration option is. The command
113<option>nixos-option</option> allows you to find out:
114
115<screen>
116$ nixos-option services.xserver.enable
117true
118
119$ nixos-option boot.kernelModules
120[ "tun" "ipv6" "loop" <replaceable>...</replaceable> ]
121</screen>
122
123Interactive exploration of the configuration is possible using
124<command
125xlink:href="https://github.com/edolstra/nix-repl">nix-repl</command>,
126a read-eval-print loop for Nix expressions. It’s not installed by
127default; run <literal>nix-env -i nix-repl</literal> to get it. A
128typical use:
129
130<screen>
131$ nix-repl '<nixpkgs/nixos>'
132
133nix-repl> config.networking.hostName
134"mandark"
135
136nix-repl> map (x: x.hostName) config.services.httpd.virtualHosts
137[ "example.org" "example.gov" ]
138</screen>
139
140</para>
141
142</section>