summary refs log tree commit diff
path: root/nixos/doc/manual/configuration/modularity.section.md
blob: 3395ace20c4fd820446aeb8b785c94c65c5a269f (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
# Modularity {#sec-modularity}

The NixOS configuration mechanism is modular. If your
`configuration.nix` 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.

Modules have exactly the same syntax as `configuration.nix`. In fact,
`configuration.nix` is itself a module. You can use other modules by
including them from `configuration.nix`, e.g.:

```nix
{ config, pkgs, ... }:

{ imports = [ ./vpn.nix ./kde.nix ];
  services.httpd.enable = true;
  environment.systemPackages = [ pkgs.emacs ];
  ...
}
```

Here, we include two modules from the same directory, `vpn.nix` and
`kde.nix`. The latter might look like this:

```nix
{ config, pkgs, ... }:

{ services.xserver.enable = true;
  services.xserver.displayManager.sddm.enable = true;
  services.xserver.desktopManager.plasma5.enable = true;
  environment.systemPackages = [ pkgs.vim ];
}
```

Note that both `configuration.nix` and `kde.nix` define the option
[](#opt-environment.systemPackages). When multiple modules define an
option, NixOS will try to *merge* the definitions. In the case of
[](#opt-environment.systemPackages), that's easy: the lists of
packages can simply be concatenated. The value in `configuration.nix` 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 `mkBefore`:

```nix
boot.kernelModules = mkBefore [ "kvm-intel" ];
```

This causes the `kvm-intel` kernel module to be loaded before any other
kernel modules.

For other types of options, a merge may not be possible. For instance,
if two modules define [](#opt-services.httpd.adminAddr),
`nixos-rebuild` will give an error:

```plain
The unique option `services.httpd.adminAddr' is defined multiple times, in `/etc/nixos/httpd.nix' and `/etc/nixos/configuration.nix'.
```

When that happens, it's possible to force one definition take precedence
over the others:

```nix
services.httpd.adminAddr = pkgs.lib.mkForce "bob@example.org";
```

When using multiple modules, you may need to access configuration values
defined in other modules. This is what the `config` function argument is
for: it contains the complete, merged system configuration. That is,
`config` is the result of combining the configurations returned by every
module [^1] . For example, here is a module that adds some packages to
[](#opt-environment.systemPackages) only if
[](#opt-services.xserver.enable) is set to `true` somewhere else:

```nix
{ config, pkgs, ... }:

{ environment.systemPackages =
    if config.services.xserver.enable then
      [ pkgs.firefox
        pkgs.thunderbird
      ]
    else
      [ ];
}
```

With multiple modules, it may not be obvious what the final value of a
configuration option is. The command `nixos-option` allows you to find
out:

```ShellSession
$ nixos-option services.xserver.enable
true

$ nixos-option boot.kernelModules
[ "tun" "ipv6" "loop" ... ]
```

Interactive exploration of the configuration is possible using `nix
  repl`, a read-eval-print loop for Nix expressions. A typical use:

```ShellSession
$ nix repl '<nixpkgs/nixos>'

nix-repl> config.networking.hostName
"mandark"

nix-repl> map (x: x.hostName) config.services.httpd.virtualHosts
[ "example.org" "example.gov" ]
```

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.

```nix
{ config, pkgs, ... }:

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

in

{ imports = [ (netConfig "nixos.localdomain") ]; }
```

[^1]: If you're wondering how it's possible that the (indirect) *result*
    of a function is passed as an *input* 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.