summary refs log tree commit diff
path: root/nixos/doc/manual/configuration/modularity.xml
blob: 7ad0ae80a48af09f8626fff30283511b3d36e6db (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
<section xmlns="http://docbook.org/ns/docbook"
         xmlns:xlink="http://www.w3.org/1999/xlink"
         xmlns:xi="http://www.w3.org/2001/XInclude"
         version="5.0"
         xml:id="sec-modularity">
 <title>Modularity</title>

 <para>
  The NixOS configuration mechanism is modular. If your
  <filename>configuration.nix</filename> becomes too big, you can split it into
  multiple files. Likewise, if you have multiple NixOS configurations (e.g. for
  different computers) with some commonality, you can move the common
  configuration into a shared file.
 </para>

 <para>
  Modules have exactly the same syntax as
  <filename>configuration.nix</filename>. In fact,
  <filename>configuration.nix</filename> is itself a module. You can use other
  modules by including them from <filename>configuration.nix</filename>, e.g.:
<programlisting>
{ config, pkgs, ... }:

{ imports = [ ./vpn.nix ./kde.nix ];
  <xref linkend="opt-services.httpd.enable"/> = true;
  <xref linkend="opt-environment.systemPackages"/> = [ pkgs.emacs ];
  <replaceable>...</replaceable>
}
</programlisting>
  Here, we include two modules from the same directory,
  <filename>vpn.nix</filename> and <filename>kde.nix</filename>. The latter
  might look like this:
<programlisting>
{ config, pkgs, ... }:

{ <xref linkend="opt-services.xserver.enable"/> = true;
  <xref linkend="opt-services.xserver.displayManager.sddm.enable"/> = true;
  <xref linkend="opt-services.xserver.desktopManager.plasma5.enable"/> = true;
}
</programlisting>
  Note that both <filename>configuration.nix</filename> and
  <filename>kde.nix</filename> define the option
  <xref linkend="opt-environment.systemPackages"/>. When multiple modules
  define an option, NixOS will try to <emphasis>merge</emphasis> the
  definitions. In the case of <xref linkend="opt-environment.systemPackages"/>,
  that’s easy: the lists of packages can simply be concatenated. The value in
  <filename>configuration.nix</filename> is merged last, so for list-type
  options, it will appear at the end of the merged list. If you want it to
  appear first, you can use <varname>mkBefore</varname>:
<programlisting>
<xref linkend="opt-boot.kernelModules"/> = mkBefore [ "kvm-intel" ];
</programlisting>
  This causes the <literal>kvm-intel</literal> kernel module to be loaded
  before any other kernel modules.
 </para>

 <para>
  For other types of options, a merge may not be possible. For instance, if two
  modules define <xref linkend="opt-services.httpd.adminAddr"/>,
  <command>nixos-rebuild</command> will give an error:
<screen>
The unique option `services.httpd.adminAddr' is defined multiple times, in `/etc/nixos/httpd.nix' and `/etc/nixos/configuration.nix'.
</screen>
  When that happens, it’s possible to force one definition take precedence
  over the others:
<programlisting>
<xref linkend="opt-services.httpd.adminAddr"/> = pkgs.lib.mkForce "bob@example.org";
</programlisting>
 </para>

 <para>
  When using multiple modules, you may need to access configuration values
  defined in other modules. This is what the <varname>config</varname> function
  argument is for: it contains the complete, merged system configuration. That
  is, <varname>config</varname> is the result of combining the configurations
  returned by every module
  <footnote xml:id="footnote-nix-is-lazy">
   <para>
    If you’re wondering how it’s possible that the (indirect)
    <emphasis>result</emphasis> of a function is passed as an
    <emphasis>input</emphasis> to that same function: that’s because Nix is a
    “lazy” language  it only computes values when they are needed. This
    works as long as no individual configuration value depends on itself.
   </para>
  </footnote>
  . For example, here is a module that adds some packages to
  <xref linkend="opt-environment.systemPackages"/> only if
  <xref linkend="opt-services.xserver.enable"/> is set to
  <literal>true</literal> somewhere else:
<programlisting>
{ config, pkgs, ... }:

{ <xref linkend="opt-environment.systemPackages"/> =
    if config.<xref linkend="opt-services.xserver.enable"/> then
      [ pkgs.firefox
        pkgs.thunderbird
      ]
    else
      [ ];
}
</programlisting>
 </para>

 <para>
  With multiple modules, it may not be obvious what the final value of a
  configuration option is. The command <option>nixos-option</option> allows you
  to find out:
<screen>
<prompt>$ </prompt>nixos-option <xref linkend="opt-services.xserver.enable"/>
true

<prompt>$ </prompt>nixos-option <xref linkend="opt-boot.kernelModules"/>
[ "tun" "ipv6" "loop" <replaceable>...</replaceable> ]
</screen>
  Interactive exploration of the configuration is possible using <command>nix
  repl</command>, a read-eval-print loop for Nix expressions. A typical use:
<screen>
<prompt>$ </prompt>nix repl '&lt;nixpkgs/nixos>'

<prompt>nix-repl> </prompt>config.<xref linkend="opt-networking.hostName"/>
"mandark"

<prompt>nix-repl> </prompt>map (x: x.hostName) config.<xref linkend="opt-services.httpd.virtualHosts"/>
[ "example.org" "example.gov" ]
</screen>
 </para>

 <para>
  While abstracting your configuration, you may find it useful to generate
  modules using code, instead of writing files. The example below would have
  the same effect as importing a file which sets those options.
<programlisting>
{ config, pkgs, ... }:

let netConfig = { hostName }: {
  networking.hostName = hostName;
  networking.useDHCP = false;
};

in

{ imports = [ (netConfig "nixos.localdomain") ]; }
</programlisting>
 </para>
</section>