<section xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" xml:id="sec-modularity">
  <title>Modularity</title>
  <para>
    The NixOS configuration mechanism is modular. If your
    <literal>configuration.nix</literal> 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
    <literal>configuration.nix</literal>. In fact,
    <literal>configuration.nix</literal> is itself a module. You can use
    other modules by including them from
    <literal>configuration.nix</literal>, e.g.:
  </para>
  <programlisting language="bash">
{ config, pkgs, ... }:

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

{ services.xserver.enable = true;
  services.xserver.displayManager.sddm.enable = true;
  services.xserver.desktopManager.plasma5.enable = true;
  environment.systemPackages = [ pkgs.vim ];
}
</programlisting>
  <para>
    Note that both <literal>configuration.nix</literal> and
    <literal>kde.nix</literal> 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
    <literal>configuration.nix</literal> 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
    <literal>mkBefore</literal>:
  </para>
  <programlisting language="bash">
boot.kernelModules = mkBefore [ &quot;kvm-intel&quot; ];
</programlisting>
  <para>
    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" />,
    <literal>nixos-rebuild</literal> will give an error:
  </para>
  <programlisting>
The unique option `services.httpd.adminAddr' is defined multiple times, in `/etc/nixos/httpd.nix' and `/etc/nixos/configuration.nix'.
</programlisting>
  <para>
    When that happens, it’s possible to force one definition take
    precedence over the others:
  </para>
  <programlisting language="bash">
services.httpd.adminAddr = pkgs.lib.mkForce &quot;bob@example.org&quot;;
</programlisting>
  <para>
    When using multiple modules, you may need to access configuration
    values defined in other modules. This is what the
    <literal>config</literal> function argument is for: it contains the
    complete, merged system configuration. That is,
    <literal>config</literal> is the result of combining the
    configurations returned by every module <footnote>
      <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 <quote>lazy</quote> 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:
  </para>
  <programlisting language="bash">
{ config, pkgs, ... }:

{ environment.systemPackages =
    if config.services.xserver.enable then
      [ pkgs.firefox
        pkgs.thunderbird
      ]
    else
      [ ];
}
</programlisting>
  <para>
    With multiple modules, it may not be obvious what the final value of
    a configuration option is. The command
    <literal>nixos-option</literal> allows you to find out:
  </para>
  <programlisting>
$ nixos-option services.xserver.enable
true

$ nixos-option boot.kernelModules
[ &quot;tun&quot; &quot;ipv6&quot; &quot;loop&quot; ... ]
</programlisting>
  <para>
    Interactive exploration of the configuration is possible using
    <literal>nix repl</literal>, a read-eval-print loop for Nix
    expressions. A typical use:
  </para>
  <programlisting>
$ nix repl '&lt;nixpkgs/nixos&gt;'

nix-repl&gt; config.networking.hostName
&quot;mandark&quot;

nix-repl&gt; map (x: x.hostName) config.services.httpd.virtualHosts
[ &quot;example.org&quot; &quot;example.gov&quot; ]
</programlisting>
  <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.
  </para>
  <programlisting language="bash">
{ config, pkgs, ... }:

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

in

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