summary refs log tree commit diff
path: root/nixos/doc/manual/configuration/modularity.section.md
diff options
context:
space:
mode:
Diffstat (limited to 'nixos/doc/manual/configuration/modularity.section.md')
-rw-r--r--nixos/doc/manual/configuration/modularity.section.md133
1 files changed, 133 insertions, 0 deletions
diff --git a/nixos/doc/manual/configuration/modularity.section.md b/nixos/doc/manual/configuration/modularity.section.md
new file mode 100644
index 00000000000..3395ace20c4
--- /dev/null
+++ b/nixos/doc/manual/configuration/modularity.section.md
@@ -0,0 +1,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.