about summary refs log tree commit diff
path: root/nixpkgs/nixos/doc/manual/development
diff options
context:
space:
mode:
Diffstat (limited to 'nixpkgs/nixos/doc/manual/development')
-rw-r--r--nixpkgs/nixos/doc/manual/development/assertions.xml74
-rw-r--r--nixpkgs/nixos/doc/manual/development/building-nixos.xml33
-rw-r--r--nixpkgs/nixos/doc/manual/development/building-parts.xml121
-rw-r--r--nixpkgs/nixos/doc/manual/development/development.xml20
-rw-r--r--nixpkgs/nixos/doc/manual/development/freeform-modules.xml68
-rw-r--r--nixpkgs/nixos/doc/manual/development/importing-modules.xml56
-rw-r--r--nixpkgs/nixos/doc/manual/development/meta-attributes.xml63
-rw-r--r--nixpkgs/nixos/doc/manual/development/nixos-tests.xml19
-rw-r--r--nixpkgs/nixos/doc/manual/development/option-declarations.xml199
-rw-r--r--nixpkgs/nixos/doc/manual/development/option-def.xml99
-rw-r--r--nixpkgs/nixos/doc/manual/development/option-types.xml914
-rwxr-xr-xnixpkgs/nixos/doc/manual/development/releases.xml366
-rw-r--r--nixpkgs/nixos/doc/manual/development/replace-modules.xml79
-rw-r--r--nixpkgs/nixos/doc/manual/development/running-nixos-tests-interactively.xml49
-rw-r--r--nixpkgs/nixos/doc/manual/development/running-nixos-tests.xml36
-rw-r--r--nixpkgs/nixos/doc/manual/development/settings-options.xml216
-rw-r--r--nixpkgs/nixos/doc/manual/development/sources.xml85
-rw-r--r--nixpkgs/nixos/doc/manual/development/testing-installer.xml22
-rw-r--r--nixpkgs/nixos/doc/manual/development/writing-documentation.xml150
-rw-r--r--nixpkgs/nixos/doc/manual/development/writing-modules.xml191
-rw-r--r--nixpkgs/nixos/doc/manual/development/writing-nixos-tests.xml464
21 files changed, 3324 insertions, 0 deletions
diff --git a/nixpkgs/nixos/doc/manual/development/assertions.xml b/nixpkgs/nixos/doc/manual/development/assertions.xml
new file mode 100644
index 000000000000..32f90cf2e7c4
--- /dev/null
+++ b/nixpkgs/nixos/doc/manual/development/assertions.xml
@@ -0,0 +1,74 @@
+<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-assertions">
+ <title>Warnings and Assertions</title>
+
+ <para>
+  When configuration problems are detectable in a module, it is a good idea to
+  write an assertion or warning. Doing so provides clear feedback to the user
+  and prevents errors after the build.
+ </para>
+
+ <para>
+  Although Nix has the <literal>abort</literal> and
+  <literal>builtins.trace</literal>
+  <link xlink:href="https://nixos.org/nix/manual/#ssec-builtins">functions</link>
+  to perform such tasks, they are not ideally suited for NixOS modules. Instead
+  of these functions, you can declare your warnings and assertions using the
+  NixOS module system.
+ </para>
+
+ <section xml:id="sec-assertions-warnings">
+  <title>Warnings</title>
+
+  <para>
+   This is an example of using <literal>warnings</literal>.
+  </para>
+
+<programlisting>
+<![CDATA[
+{ config, lib, ... }:
+{
+  config = lib.mkIf config.services.foo.enable {
+    warnings =
+      if config.services.foo.bar
+      then [ ''You have enabled the bar feature of the foo service.
+               This is known to cause some specific problems in certain situations.
+               '' ]
+      else [];
+  }
+}
+]]>
+</programlisting>
+ </section>
+
+ <section xml:id="sec-assertions-assertions">
+  <title>Assertions</title>
+
+  <para>
+   This example, extracted from the
+   <link xlink:href="https://github.com/NixOS/nixpkgs/blob/release-17.09/nixos/modules/services/logging/syslogd.nix">
+   <literal>syslogd</literal> module </link> shows how to use
+   <literal>assertions</literal>. Since there can only be one active syslog
+   daemon at a time, an assertion is useful to prevent such a broken system
+   from being built.
+  </para>
+
+<programlisting>
+<![CDATA[
+{ config, lib, ... }:
+{
+  config = lib.mkIf config.services.syslogd.enable {
+    assertions =
+      [ { assertion = !config.services.rsyslogd.enable;
+          message = "rsyslogd conflicts with syslogd";
+        }
+      ];
+  }
+}
+]]>
+</programlisting>
+ </section>
+</section>
diff --git a/nixpkgs/nixos/doc/manual/development/building-nixos.xml b/nixpkgs/nixos/doc/manual/development/building-nixos.xml
new file mode 100644
index 000000000000..d58b6354d1d3
--- /dev/null
+++ b/nixpkgs/nixos/doc/manual/development/building-nixos.xml
@@ -0,0 +1,33 @@
+<chapter 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-building-cd">
+ <title>Building Your Own NixOS CD</title>
+ <para>
+  Building a NixOS CD is as easy as configuring your own computer. The idea is
+  to use another module which will replace your
+  <filename>configuration.nix</filename> to configure the system that would be
+  installed on the CD.
+ </para>
+ <para>
+  Default CD/DVD configurations are available inside
+  <filename>nixos/modules/installer/cd-dvd</filename>.
+<screen>
+<prompt>$ </prompt>git clone https://github.com/NixOS/nixpkgs.git
+<prompt>$ </prompt>cd nixpkgs/nixos
+<prompt>$ </prompt>nix-build -A config.system.build.isoImage -I nixos-config=modules/installer/cd-dvd/installation-cd-minimal.nix default.nix</screen>
+ </para>
+ <para>
+  Before burning your CD/DVD, you can check the content of the image by
+  mounting anywhere like suggested by the following command:
+<screen>
+<prompt># </prompt>mount -o loop -t iso9660 ./result/iso/cd.iso /mnt/iso</screen>
+ </para>
+ <para>
+ If you want to customize your NixOS CD in more detail, or generate other kinds
+ of images, you might want to check out <link
+ xlink:href="https://github.com/nix-community/nixos-generators">nixos-generators</link>. This can also be a good starting point when you want to use Nix to build a
+ 'minimal' image that doesn't include a NixOS installation.
+ </para>
+</chapter>
diff --git a/nixpkgs/nixos/doc/manual/development/building-parts.xml b/nixpkgs/nixos/doc/manual/development/building-parts.xml
new file mode 100644
index 000000000000..88369fb891b3
--- /dev/null
+++ b/nixpkgs/nixos/doc/manual/development/building-parts.xml
@@ -0,0 +1,121 @@
+<chapter 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-building-parts">
+ <title>Building Specific Parts of NixOS</title>
+ <para>
+  With the command <command>nix-build</command>, you can build specific parts
+  of your NixOS configuration. This is done as follows:
+<screen>
+<prompt>$ </prompt>cd <replaceable>/path/to/nixpkgs/nixos</replaceable>
+<prompt>$ </prompt>nix-build -A config.<replaceable>option</replaceable></screen>
+  where <replaceable>option</replaceable> is a NixOS option with type
+  “derivation” (i.e. something that can be built). Attributes of interest
+  include:
+  <variablelist>
+   <varlistentry>
+    <term>
+     <varname>system.build.toplevel</varname>
+    </term>
+    <listitem>
+     <para>
+      The top-level option that builds the entire NixOS system. Everything else
+      in your configuration is indirectly pulled in by this option. This is
+      what <command>nixos-rebuild</command> builds and what
+      <filename>/run/current-system</filename> points to afterwards.
+     </para>
+     <para>
+      A shortcut to build this is:
+<screen>
+<prompt>$ </prompt>nix-build -A system</screen>
+     </para>
+    </listitem>
+   </varlistentry>
+   <varlistentry>
+    <term>
+     <varname>system.build.manual.manualHTML</varname>
+    </term>
+    <listitem>
+     <para>
+      The NixOS manual.
+     </para>
+    </listitem>
+   </varlistentry>
+   <varlistentry>
+    <term>
+     <varname>system.build.etc</varname>
+    </term>
+    <listitem>
+     <para>
+      A tree of symlinks that form the static parts of
+      <filename>/etc</filename>.
+     </para>
+    </listitem>
+   </varlistentry>
+   <varlistentry>
+    <term>
+     <varname>system.build.initialRamdisk</varname>
+    </term>
+    <term>
+     <varname>system.build.kernel</varname>
+    </term>
+    <listitem>
+     <para>
+      The initial ramdisk and kernel of the system. This allows a quick way to
+      test whether the kernel and the initial ramdisk boot correctly, by using
+      QEMU’s <option>-kernel</option> and <option>-initrd</option> options:
+<screen>
+<prompt>$ </prompt>nix-build -A config.system.build.initialRamdisk -o initrd
+<prompt>$ </prompt>nix-build -A config.system.build.kernel -o kernel
+<prompt>$ </prompt>qemu-system-x86_64 -kernel ./kernel/bzImage -initrd ./initrd/initrd -hda /dev/null
+</screen>
+     </para>
+    </listitem>
+   </varlistentry>
+   <varlistentry>
+    <term>
+     <varname>system.build.nixos-rebuild</varname>
+    </term>
+    <term>
+     <varname>system.build.nixos-install</varname>
+    </term>
+    <term>
+     <varname>system.build.nixos-generate-config</varname>
+    </term>
+    <listitem>
+     <para>
+      These build the corresponding NixOS commands.
+     </para>
+    </listitem>
+   </varlistentry>
+   <varlistentry>
+    <term>
+     <varname>systemd.units.<replaceable>unit-name</replaceable>.unit</varname>
+    </term>
+    <listitem>
+     <para>
+      This builds the unit with the specified name. Note that since unit names
+      contain dots (e.g. <literal>httpd.service</literal>), you need to put
+      them between quotes, like this:
+<screen>
+<prompt>$ </prompt>nix-build -A 'config.systemd.units."httpd.service".unit'
+</screen>
+      You can also test individual units, without rebuilding the whole system,
+      by putting them in <filename>/run/systemd/system</filename>:
+<screen>
+<prompt>$ </prompt>cp $(nix-build -A 'config.systemd.units."httpd.service".unit')/httpd.service \
+    /run/systemd/system/tmp-httpd.service
+<prompt># </prompt>systemctl daemon-reload
+<prompt># </prompt>systemctl start tmp-httpd.service
+</screen>
+      Note that the unit must not have the same name as any unit in
+      <filename>/etc/systemd/system</filename> since those take precedence over
+      <filename>/run/systemd/system</filename>. That’s why the unit is
+      installed as <filename>tmp-httpd.service</filename> here.
+     </para>
+    </listitem>
+   </varlistentry>
+  </variablelist>
+ </para>
+</chapter>
diff --git a/nixpkgs/nixos/doc/manual/development/development.xml b/nixpkgs/nixos/doc/manual/development/development.xml
new file mode 100644
index 000000000000..43f511b3e96b
--- /dev/null
+++ b/nixpkgs/nixos/doc/manual/development/development.xml
@@ -0,0 +1,20 @@
+<part   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="ch-development">
+ <title>Development</title>
+ <partintro xml:id="ch-development-intro">
+  <para>
+   This chapter describes how you can modify and extend NixOS.
+  </para>
+ </partintro>
+ <xi:include href="sources.xml" />
+ <xi:include href="writing-modules.xml" />
+ <xi:include href="building-parts.xml" />
+ <xi:include href="writing-documentation.xml" />
+ <xi:include href="building-nixos.xml" />
+ <xi:include href="nixos-tests.xml" />
+ <xi:include href="testing-installer.xml" />
+ <xi:include href="releases.xml" />
+</part>
diff --git a/nixpkgs/nixos/doc/manual/development/freeform-modules.xml b/nixpkgs/nixos/doc/manual/development/freeform-modules.xml
new file mode 100644
index 000000000000..257e6b11bf01
--- /dev/null
+++ b/nixpkgs/nixos/doc/manual/development/freeform-modules.xml
@@ -0,0 +1,68 @@
+<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-freeform-modules">
+ <title>Freeform modules</title>
+ <para>
+  Freeform modules allow you to define values for option paths that have not been declared explicitly. This can be used to add attribute-specific types to what would otherwise have to be <literal>attrsOf</literal> options in order to accept all attribute names.
+ </para>
+ <para>
+  This feature can be enabled by using the attribute <literal>freeformType</literal> to define a freeform type. By doing this, all assignments without an associated option will be merged using the freeform type and combined into the resulting <literal>config</literal> set. Since this feature nullifies name checking for entire option trees, it is only recommended for use in submodules.
+ </para>
+ <example xml:id="ex-freeform-module">
+  <title>Freeform submodule</title>
+  <para>
+   The following shows a submodule assigning a freeform type that allows arbitrary attributes with <literal>str</literal> values below <literal>settings</literal>, but also declares an option for the <literal>settings.port</literal> attribute to have it type-checked and assign a default value. See <xref linkend="ex-settings-typed-attrs"/> for a more complete example.
+  </para>
+ <programlisting>
+{ lib, config, ... }: {
+
+  options.settings = lib.mkOption {
+    type = lib.types.submodule {
+
+      freeformType = with lib.types; attrsOf str;
+
+      # We want this attribute to be checked for the correct type
+      options.port = lib.mkOption {
+        type = lib.types.port;
+        # Declaring the option also allows defining a default value
+        default = 8080;
+      };
+
+    };
+  };
+}
+ </programlisting>
+ <para>
+  And the following shows what such a module then allows
+ </para>
+ <programlisting>
+{
+  # Not a declared option, but the freeform type allows this
+  settings.logLevel = "debug";
+
+  # Not allowed because the the freeform type only allows strings
+  # settings.enable = true;
+
+  # Allowed because there is a port option declared
+  settings.port = 80;
+
+  # Not allowed because the port option doesn't allow strings
+  # settings.port = "443";
+}
+ </programlisting>
+ </example>
+ <note>
+  <para>
+   Freeform attributes cannot depend on other attributes of the same set without infinite recursion:
+<programlisting>
+{
+  # This throws infinite recursion encountered
+  settings.logLevel = lib.mkIf (config.settings.port == 80) "debug";
+}
+</programlisting>
+   To prevent this, declare options for all attributes that need to depend on others. For above example this means to declare <literal>logLevel</literal> to be an option.
+  </para>
+ </note>
+</section>
diff --git a/nixpkgs/nixos/doc/manual/development/importing-modules.xml b/nixpkgs/nixos/doc/manual/development/importing-modules.xml
new file mode 100644
index 000000000000..1c6a5671eda8
--- /dev/null
+++ b/nixpkgs/nixos/doc/manual/development/importing-modules.xml
@@ -0,0 +1,56 @@
+<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-importing-modules">
+ <title>Importing Modules</title>
+
+ <para>
+  Sometimes NixOS modules need to be used in configuration but exist outside of
+  Nixpkgs. These modules can be imported:
+ </para>
+
+<programlisting>
+{ config, lib, pkgs, ... }:
+
+{
+  imports =
+    [ # Use a locally-available module definition in
+      # ./example-module/default.nix
+        ./example-module
+    ];
+
+  services.exampleModule.enable = true;
+}
+</programlisting>
+
+ <para>
+  The environment variable <literal>NIXOS_EXTRA_MODULE_PATH</literal> is an
+  absolute path to a NixOS module that is included alongside the Nixpkgs NixOS
+  modules. Like any NixOS module, this module can import additional modules:
+ </para>
+
+<programlisting>
+# ./module-list/default.nix
+[
+  ./example-module1
+  ./example-module2
+]
+</programlisting>
+
+<programlisting>
+# ./extra-module/default.nix
+{ imports = import ./module-list.nix; }
+</programlisting>
+
+<programlisting>
+# NIXOS_EXTRA_MODULE_PATH=/absolute/path/to/extra-module
+{ config, lib, pkgs, ... }:
+
+{
+  # No `imports` needed
+
+  services.exampleModule1.enable = true;
+}
+</programlisting>
+</section>
diff --git a/nixpkgs/nixos/doc/manual/development/meta-attributes.xml b/nixpkgs/nixos/doc/manual/development/meta-attributes.xml
new file mode 100644
index 000000000000..c40be0a50c36
--- /dev/null
+++ b/nixpkgs/nixos/doc/manual/development/meta-attributes.xml
@@ -0,0 +1,63 @@
+<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-meta-attributes">
+ <title>Meta Attributes</title>
+
+ <para>
+  Like Nix packages, NixOS modules can declare meta-attributes to provide extra
+  information. Module meta attributes are defined in the
+  <filename
+    xlink:href="https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/misc/meta.nix">meta.nix</filename>
+  special module.
+ </para>
+
+ <para>
+  <literal>meta</literal> is a top level attribute like
+  <literal>options</literal> and <literal>config</literal>. Available
+  meta-attributes are <literal>maintainers</literal> and
+  <literal>doc</literal>.
+ </para>
+
+ <para>
+  Each of the meta-attributes must be defined at most once per module file.
+ </para>
+
+<programlisting>
+{ config, lib, pkgs, ... }:
+{
+  options = {
+    ...
+  };
+
+  config = {
+    ...
+  };
+
+  meta = {
+    maintainers = with lib.maintainers; [ ericsagnes ]; <co
+      xml:id='modules-meta-1' />
+    doc = ./default.xml; <co xml:id='modules-meta-2' />
+  };
+}
+</programlisting>
+
+ <calloutlist>
+  <callout arearefs='modules-meta-1'>
+   <para>
+    <varname>maintainers</varname> contains a list of the module maintainers.
+   </para>
+  </callout>
+  <callout arearefs='modules-meta-2'>
+   <para>
+    <varname>doc</varname> points to a valid DocBook file containing the module
+    documentation. Its contents is automatically added to
+    <xref
+      linkend="ch-configuration"/>. Changes to a module documentation
+    have to be checked to not break building the NixOS manual:
+   </para>
+<screen><prompt>$ </prompt>nix-build nixos/release.nix -A manual.x86_64-linux</screen>
+  </callout>
+ </calloutlist>
+</section>
diff --git a/nixpkgs/nixos/doc/manual/development/nixos-tests.xml b/nixpkgs/nixos/doc/manual/development/nixos-tests.xml
new file mode 100644
index 000000000000..2695082e3867
--- /dev/null
+++ b/nixpkgs/nixos/doc/manual/development/nixos-tests.xml
@@ -0,0 +1,19 @@
+<chapter 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-nixos-tests">
+ <title>NixOS Tests</title>
+ <para>
+  When you add some feature to NixOS, you should write a test for it. NixOS
+  tests are kept in the directory
+  <filename
+xlink:href="https://github.com/NixOS/nixpkgs/tree/master/nixos/tests">nixos/tests</filename>,
+  and are executed (using Nix) by a testing framework that automatically starts
+  one or more virtual machines containing the NixOS system(s) required for the
+  test.
+ </para>
+ <xi:include href="writing-nixos-tests.xml" />
+ <xi:include href="running-nixos-tests.xml" />
+ <xi:include href="running-nixos-tests-interactively.xml" />
+</chapter>
diff --git a/nixpkgs/nixos/doc/manual/development/option-declarations.xml b/nixpkgs/nixos/doc/manual/development/option-declarations.xml
new file mode 100644
index 000000000000..56ebf4816306
--- /dev/null
+++ b/nixpkgs/nixos/doc/manual/development/option-declarations.xml
@@ -0,0 +1,199 @@
+<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-option-declarations">
+ <title>Option Declarations</title>
+
+ <para>
+  An option declaration specifies the name, type and description of a NixOS
+  configuration option. It is invalid to define an option that hasn’t been
+  declared in any module. An option declaration generally looks like this:
+<programlisting>
+options = {
+  <replaceable>name</replaceable> = mkOption {
+    type = <replaceable>type specification</replaceable>;
+    default = <replaceable>default value</replaceable>;
+    example = <replaceable>example value</replaceable>;
+    description = "<replaceable>Description for use in the NixOS manual.</replaceable>";
+  };
+};
+</programlisting>
+  The attribute names within the <replaceable>name</replaceable> attribute path
+  must be camel cased in general but should, as an exception, match the
+  <link
+xlink:href="https://nixos.org/nixpkgs/manual/#sec-package-naming">
+  package attribute name</link> when referencing a Nixpkgs package. For
+  example, the option <varname>services.nix-serve.bindAddress</varname>
+  references the <varname>nix-serve</varname> Nixpkgs package.
+ </para>
+
+ <para>
+  The function <varname>mkOption</varname> accepts the following arguments.
+  <variablelist>
+   <varlistentry>
+    <term>
+     <varname>type</varname>
+    </term>
+    <listitem>
+     <para>
+      The type of the option (see <xref linkend='sec-option-types' />). It may
+      be omitted, but that’s not advisable since it may lead to errors that
+      are hard to diagnose.
+     </para>
+    </listitem>
+   </varlistentry>
+   <varlistentry>
+    <term>
+     <varname>default</varname>
+    </term>
+    <listitem>
+     <para>
+      The default value used if no value is defined by any module. A default is
+      not required; but if a default is not given, then users of the module
+      will have to define the value of the option, otherwise an error will be
+      thrown.
+     </para>
+    </listitem>
+   </varlistentry>
+   <varlistentry>
+    <term>
+     <varname>example</varname>
+    </term>
+    <listitem>
+     <para>
+      An example value that will be shown in the NixOS manual.
+     </para>
+    </listitem>
+   </varlistentry>
+   <varlistentry>
+    <term>
+     <varname>description</varname>
+    </term>
+    <listitem>
+     <para>
+      A textual description of the option, in DocBook format, that will be
+      included in the NixOS manual.
+     </para>
+    </listitem>
+   </varlistentry>
+  </variablelist>
+ </para>
+
+ <section xml:id="sec-option-declarations-eot">
+  <title>Extensible Option Types</title>
+
+  <para>
+   Extensible option types is a feature that allow to extend certain types
+   declaration through multiple module files. This feature only work with a
+   restricted set of types, namely <literal>enum</literal> and
+   <literal>submodules</literal> and any composed forms of them.
+  </para>
+
+  <para>
+   Extensible option types can be used for <literal>enum</literal> options that
+   affects multiple modules, or as an alternative to related
+   <literal>enable</literal> options.
+  </para>
+
+  <para>
+   As an example, we will take the case of display managers. There is a central
+   display manager module for generic display manager options and a module file
+   per display manager backend (sddm, gdm ...).
+  </para>
+
+  <para>
+   There are two approach to this module structure:
+   <itemizedlist>
+    <listitem>
+     <para>
+      Managing the display managers independently by adding an enable option to
+      every display manager module backend. (NixOS)
+     </para>
+    </listitem>
+    <listitem>
+     <para>
+      Managing the display managers in the central module by adding an option
+      to select which display manager backend to use.
+     </para>
+    </listitem>
+   </itemizedlist>
+  </para>
+
+  <para>
+   Both approaches have problems.
+  </para>
+
+  <para>
+   Making backends independent can quickly become hard to manage. For display
+   managers, there can be only one enabled at a time, but the type system can
+   not enforce this restriction as there is no relation between each backend
+   <literal>enable</literal> option. As a result, this restriction has to be
+   done explicitely by adding assertions in each display manager backend
+   module.
+  </para>
+
+  <para>
+   On the other hand, managing the display managers backends in the central
+   module will require to change the central module option every time a new
+   backend is added or removed.
+  </para>
+
+  <para>
+   By using extensible option types, it is possible to create a placeholder
+   option in the central module
+   (<xref linkend='ex-option-declaration-eot-service'
+      />), and to extend
+   it in each backend module
+   (<xref
+      linkend='ex-option-declaration-eot-backend-gdm' />,
+   <xref
+      linkend='ex-option-declaration-eot-backend-sddm' />).
+  </para>
+
+  <para>
+   As a result, <literal>displayManager.enable</literal> option values can be
+   added without changing the main service module file and the type system
+   automatically enforce that there can only be a single display manager
+   enabled.
+  </para>
+
+  <example xml:id='ex-option-declaration-eot-service'>
+   <title>Extensible type placeholder in the service module</title>
+<screen>
+services.xserver.displayManager.enable = mkOption {
+  description = "Display manager to use";
+  type = with types; nullOr (enum [ ]);
+};</screen>
+  </example>
+
+  <example xml:id='ex-option-declaration-eot-backend-gdm'>
+   <title>Extending <literal>services.xserver.displayManager.enable</literal> in the <literal>gdm</literal> module</title>
+<screen>
+services.xserver.displayManager.enable = mkOption {
+  type = with types; nullOr (enum [ "gdm" ]);
+};</screen>
+  </example>
+
+  <example xml:id='ex-option-declaration-eot-backend-sddm'>
+   <title>Extending <literal>services.xserver.displayManager.enable</literal> in the <literal>sddm</literal> module</title>
+<screen>
+services.xserver.displayManager.enable = mkOption {
+  type = with types; nullOr (enum [ "sddm" ]);
+};</screen>
+  </example>
+
+  <para>
+   The placeholder declaration is a standard <literal>mkOption</literal>
+   declaration, but it is important that extensible option declarations only
+   use the <literal>type</literal> argument.
+  </para>
+
+  <para>
+   Extensible option types work with any of the composed variants of
+   <literal>enum</literal> such as <literal>with types; nullOr (enum [ "foo"
+   "bar" ])</literal> or <literal>with types; listOf (enum [ "foo" "bar"
+   ])</literal>.
+  </para>
+ </section>
+</section>
diff --git a/nixpkgs/nixos/doc/manual/development/option-def.xml b/nixpkgs/nixos/doc/manual/development/option-def.xml
new file mode 100644
index 000000000000..50a705d0cb8e
--- /dev/null
+++ b/nixpkgs/nixos/doc/manual/development/option-def.xml
@@ -0,0 +1,99 @@
+<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-option-definitions">
+ <title>Option Definitions</title>
+
+ <para>
+  Option definitions are generally straight-forward bindings of values to
+  option names, like
+<programlisting>
+config = {
+  services.httpd.enable = true;
+};
+</programlisting>
+  However, sometimes you need to wrap an option definition or set of option
+  definitions in a <emphasis>property</emphasis> to achieve certain effects:
+ </para>
+
+ <simplesect xml:id="sec-option-definitions-delaying-conditionals">
+  <title>Delaying Conditionals</title>
+  <para>
+   If a set of option definitions is conditional on the value of another
+   option, you may need to use <varname>mkIf</varname>. Consider, for instance:
+<programlisting>
+config = if config.services.httpd.enable then {
+  environment.systemPackages = [ <replaceable>...</replaceable> ];
+  <replaceable>...</replaceable>
+} else {};
+</programlisting>
+   This definition will cause Nix to fail with an “infinite recursion”
+   error. Why? Because the value of
+   <option>config.services.httpd.enable</option> depends on the value being
+   constructed here. After all, you could also write the clearly circular and
+   contradictory:
+<programlisting>
+config = if config.services.httpd.enable then {
+  services.httpd.enable = false;
+} else {
+  services.httpd.enable = true;
+};
+</programlisting>
+   The solution is to write:
+<programlisting>
+config = mkIf config.services.httpd.enable {
+  environment.systemPackages = [ <replaceable>...</replaceable> ];
+  <replaceable>...</replaceable>
+};
+</programlisting>
+   The special function <varname>mkIf</varname> causes the evaluation of the
+   conditional to be “pushed down” into the individual definitions, as if
+   you had written:
+<programlisting>
+config = {
+  environment.systemPackages = if config.services.httpd.enable then [ <replaceable>...</replaceable> ] else [];
+  <replaceable>...</replaceable>
+};
+</programlisting>
+  </para>
+ </simplesect>
+
+ <simplesect xml:id="sec-option-definitions-setting-priorities">
+  <title>Setting Priorities</title>
+  <para>
+   A module can override the definitions of an option in other modules by
+   setting a <emphasis>priority</emphasis>. All option definitions that do not
+   have the lowest priority value are discarded. By default, option definitions
+   have priority 1000. You can specify an explicit priority by using
+   <varname>mkOverride</varname>, e.g.
+<programlisting>
+services.openssh.enable = mkOverride 10 false;
+</programlisting>
+   This definition causes all other definitions with priorities above 10 to be
+   discarded. The function <varname>mkForce</varname> is equal to
+   <varname>mkOverride 50</varname>.
+  </para>
+ </simplesect>
+
+ <simplesect xml:id="sec-option-definitions-merging">
+  <title>Merging Configurations</title>
+  <para>
+   In conjunction with <literal>mkIf</literal>, it is sometimes useful for a
+   module to return multiple sets of option definitions, to be merged together
+   as if they were declared in separate modules. This can be done using
+   <varname>mkMerge</varname>:
+<programlisting>
+config = mkMerge
+  [ # Unconditional stuff.
+    { environment.systemPackages = [ <replaceable>...</replaceable> ];
+    }
+    # Conditional stuff.
+    (mkIf config.services.bla.enable {
+      environment.systemPackages = [ <replaceable>...</replaceable> ];
+    })
+  ];
+</programlisting>
+  </para>
+ </simplesect>
+</section>
diff --git a/nixpkgs/nixos/doc/manual/development/option-types.xml b/nixpkgs/nixos/doc/manual/development/option-types.xml
new file mode 100644
index 000000000000..3d2191e2f3f3
--- /dev/null
+++ b/nixpkgs/nixos/doc/manual/development/option-types.xml
@@ -0,0 +1,914 @@
+<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-option-types">
+ <title>Options Types</title>
+
+ <para>
+  Option types are a way to put constraints on the values a module option can
+  take. Types are also responsible of how values are merged in case of multiple
+  value definitions.
+ </para>
+
+ <section xml:id="sec-option-types-basic">
+  <title>Basic Types</title>
+
+  <para>
+   Basic types are the simplest available types in the module system. Basic
+   types include multiple string types that mainly differ in how definition
+   merging is handled.
+  </para>
+
+  <variablelist>
+   <varlistentry>
+    <term>
+     <varname>types.bool</varname>
+    </term>
+    <listitem>
+     <para>
+      A boolean, its values can be <literal>true</literal> or
+      <literal>false</literal>.
+     </para>
+    </listitem>
+   </varlistentry>
+   <varlistentry>
+    <term>
+     <varname>types.path</varname>
+    </term>
+    <listitem>
+     <para>
+      A filesystem path, defined as anything that when coerced to a string
+      starts with a slash. Even if derivations can be considered as path, the
+      more specific <literal>types.package</literal> should be preferred.
+     </para>
+    </listitem>
+   </varlistentry>
+   <varlistentry>
+    <term>
+     <varname>types.package</varname>
+    </term>
+    <listitem>
+     <para>
+      A derivation or a store path.
+     </para>
+    </listitem>
+   </varlistentry>
+   <varlistentry>
+    <term>
+     <varname>types.anything</varname>
+    </term>
+    <listitem>
+     <para>
+      A type that accepts any value and recursively merges attribute sets together.
+      This type is recommended when the option type is unknown.
+      <example xml:id="ex-types-anything">
+       <title><literal>types.anything</literal> Example</title>
+       <para>
+        Two definitions of this type like
+<programlisting>
+{
+  str = lib.mkDefault "foo";
+  pkg.hello = pkgs.hello;
+  fun.fun = x: x + 1;
+}
+</programlisting>
+<programlisting>
+{
+  str = lib.mkIf true "bar";
+  pkg.gcc = pkgs.gcc;
+  fun.fun = lib.mkForce (x: x + 2);
+}
+</programlisting>
+        will get merged to
+<programlisting>
+{
+  str = "bar";
+  pkg.gcc = pkgs.gcc;
+  pkg.hello = pkgs.hello;
+  fun.fun = x: x + 2;
+}
+</programlisting>
+       </para>
+      </example>
+     </para>
+    </listitem>
+   </varlistentry>
+   <varlistentry>
+    <term>
+     <varname>types.attrs</varname>
+    </term>
+    <listitem>
+     <para>
+      A free-form attribute set.
+      <warning><para>
+       This type will be deprecated in the future because it doesn't recurse
+       into attribute sets, silently drops earlier attribute definitions, and
+       doesn't discharge <literal>lib.mkDefault</literal>, <literal>lib.mkIf
+       </literal> and co. For allowing arbitrary attribute sets, prefer
+       <literal>types.attrsOf types.anything</literal> instead which doesn't
+       have these problems.
+      </para></warning>
+     </para>
+    </listitem>
+   </varlistentry>
+  </variablelist>
+
+  <para>
+   Integer-related types:
+  </para>
+
+  <variablelist>
+   <varlistentry>
+    <term>
+     <varname>types.int</varname>
+    </term>
+    <listitem>
+     <para>
+      A signed integer.
+     </para>
+    </listitem>
+   </varlistentry>
+   <varlistentry>
+    <term>
+     <varname>types.ints.{s8, s16, s32}</varname>
+    </term>
+    <listitem>
+     <para>
+      Signed integers with a fixed length (8, 16 or 32 bits). They go from
+      <inlineequation><mathphrase>−2<superscript>n</superscript>/2</mathphrase>
+      </inlineequation> to <inlineequation>
+      <mathphrase>2<superscript>n</superscript>/2−1</mathphrase>
+      </inlineequation> respectively (e.g. <literal>−128</literal> to
+      <literal>127</literal> for 8 bits).
+     </para>
+    </listitem>
+   </varlistentry>
+   <varlistentry>
+    <term>
+     <varname>types.ints.unsigned</varname>
+    </term>
+    <listitem>
+     <para>
+      An unsigned integer (that is >= 0).
+     </para>
+    </listitem>
+   </varlistentry>
+   <varlistentry xml:id='types.ints.ux'>
+    <term>
+     <varname>types.ints.{u8, u16, u32}</varname>
+    </term>
+    <listitem>
+     <para>
+      Unsigned integers with a fixed length (8, 16 or 32 bits). They go from
+      <inlineequation><mathphrase>0</mathphrase></inlineequation> to
+      <inlineequation>
+      <mathphrase>2<superscript>n</superscript>−1</mathphrase>
+      </inlineequation> respectively (e.g. <literal>0</literal> to
+      <literal>255</literal> for 8 bits).
+     </para>
+    </listitem>
+   </varlistentry>
+   <varlistentry>
+    <term>
+     <varname>types.ints.positive</varname>
+    </term>
+    <listitem>
+     <para>
+      A positive integer (that is > 0).
+     </para>
+    </listitem>
+   </varlistentry>
+   <varlistentry>
+    <term>
+     <varname>types.port</varname>
+    </term>
+    <listitem>
+     <para>
+      A port number. This type is an alias to
+      <link linkend='types.ints.ux'><varname>types.ints.u16</varname></link>.
+     </para>
+    </listitem>
+   </varlistentry>
+  </variablelist>
+
+  <para>
+   String-related types:
+  </para>
+
+  <variablelist>
+   <varlistentry>
+    <term>
+     <varname>types.str</varname>
+    </term>
+    <listitem>
+     <para>
+      A string. Multiple definitions cannot be merged.
+     </para>
+    </listitem>
+   </varlistentry>
+   <varlistentry>
+    <term>
+     <varname>types.lines</varname>
+    </term>
+    <listitem>
+     <para>
+      A string. Multiple definitions are concatenated with a new line
+      <literal>"\n"</literal>.
+     </para>
+    </listitem>
+   </varlistentry>
+   <varlistentry>
+    <term>
+     <varname>types.commas</varname>
+    </term>
+    <listitem>
+     <para>
+      A string. Multiple definitions are concatenated with a comma
+      <literal>","</literal>.
+     </para>
+    </listitem>
+   </varlistentry>
+   <varlistentry>
+    <term>
+     <varname>types.envVar</varname>
+    </term>
+    <listitem>
+     <para>
+      A string. Multiple definitions are concatenated with a collon
+      <literal>":"</literal>.
+     </para>
+    </listitem>
+   </varlistentry>
+   <varlistentry>
+    <term>
+     <varname>types.strMatching</varname>
+    </term>
+    <listitem>
+     <para>
+      A string matching a specific regular expression. Multiple definitions
+      cannot be merged. The regular expression is processed using
+      <literal>builtins.match</literal>.
+     </para>
+    </listitem>
+   </varlistentry>
+  </variablelist>
+ </section>
+
+ <section xml:id="sec-option-types-value">
+  <title>Value Types</title>
+
+  <para>
+   Value types are types that take a value parameter.
+  </para>
+
+  <variablelist>
+   <varlistentry>
+    <term>
+     <varname>types.enum</varname> <replaceable>l</replaceable>
+    </term>
+    <listitem>
+     <para>
+      One element of the list <replaceable>l</replaceable>, e.g.
+      <literal>types.enum [ "left" "right" ]</literal>. Multiple definitions
+      cannot be merged.
+     </para>
+    </listitem>
+   </varlistentry>
+   <varlistentry>
+    <term>
+     <varname>types.separatedString</varname> <replaceable>sep</replaceable>
+    </term>
+    <listitem>
+     <para>
+      A string with a custom separator <replaceable>sep</replaceable>, e.g.
+      <literal>types.separatedString "|"</literal>.
+     </para>
+    </listitem>
+   </varlistentry>
+   <varlistentry>
+    <term>
+     <varname>types.ints.between</varname> <replaceable>lowest</replaceable> <replaceable>highest</replaceable>
+    </term>
+    <listitem>
+     <para>
+      An integer between <replaceable>lowest</replaceable> and
+      <replaceable>highest</replaceable> (both inclusive). Useful for creating
+      types like <literal>types.port</literal>.
+     </para>
+    </listitem>
+   </varlistentry>
+   <varlistentry>
+    <term>
+     <varname>types.submodule</varname> <replaceable>o</replaceable>
+    </term>
+    <listitem>
+     <para>
+      A set of sub options <replaceable>o</replaceable>.
+      <replaceable>o</replaceable> can be an attribute set, a function
+      returning an attribute set, or a path to a file containing such a value. Submodules are used in
+      composed types to create modular options. This is equivalent to
+      <literal>types.submoduleWith { modules = toList o; shorthandOnlyDefinesConfig = true; }</literal>.
+      Submodules are detailed in
+      <xref
+          linkend='section-option-types-submodule' />.
+     </para>
+    </listitem>
+   </varlistentry>
+   <varlistentry>
+     <term>
+       <varname>types.submoduleWith</varname> {
+        <replaceable>modules</replaceable>,
+        <replaceable>specialArgs</replaceable> ? {},
+        <replaceable>shorthandOnlyDefinesConfig</replaceable> ? false }
+     </term>
+     <listitem>
+       <para>
+         Like <varname>types.submodule</varname>, but more flexible and with better defaults.
+         It has parameters
+         <itemizedlist>
+           <listitem><para>
+             <replaceable>modules</replaceable>
+             A list of modules to use by default for this submodule type. This gets combined
+             with all option definitions to build the final list of modules that will be included.
+             <note><para>
+               Only options defined with this argument are included in rendered documentation.
+             </para></note>
+           </para></listitem>
+           <listitem><para>
+             <replaceable>specialArgs</replaceable>
+             An attribute set of extra arguments to be passed to the module functions.
+             The option <literal>_module.args</literal> should be used instead
+             for most arguments since it allows overriding. <replaceable>specialArgs</replaceable> should only be
+             used for arguments that can&apos;t go through the module fixed-point, because of
+             infinite recursion or other problems. An example is overriding the
+             <varname>lib</varname> argument, because <varname>lib</varname> itself is used
+             to define <literal>_module.args</literal>, which makes using
+             <literal>_module.args</literal> to define it impossible.
+           </para></listitem>
+           <listitem><para>
+             <replaceable>shorthandOnlyDefinesConfig</replaceable>
+             Whether definitions of this type should default to the <literal>config</literal>
+             section of a module (see <xref linkend='ex-module-syntax'/>) if it is an attribute
+             set. Enabling this only has a benefit when the submodule defines an option named
+             <literal>config</literal> or <literal>options</literal>. In such a case it would
+             allow the option to be set with <literal>the-submodule.config = "value"</literal>
+             instead of requiring <literal>the-submodule.config.config = "value"</literal>.
+             This is because only when modules <emphasis>don&apos;t</emphasis> set the
+             <literal>config</literal> or <literal>options</literal> keys, all keys are interpreted
+             as option definitions in the <literal>config</literal> section. Enabling this option
+             implicitly puts all attributes in the <literal>config</literal> section.
+           </para>
+           <para>
+             With this option enabled, defining a non-<literal>config</literal> section requires
+             using a function: <literal>the-submodule = { ... }: { options = { ... }; }</literal>.
+           </para></listitem>
+         </itemizedlist>
+       </para>
+     </listitem>
+   </varlistentry>
+  </variablelist>
+ </section>
+
+ <section xml:id="sec-option-types-composed">
+  <title>Composed Types</title>
+
+  <para>
+   Composed types are types that take a type as parameter. <literal>listOf
+   int</literal> and <literal>either int str</literal> are examples of composed
+   types.
+  </para>
+
+  <variablelist>
+   <varlistentry>
+    <term>
+     <varname>types.listOf</varname> <replaceable>t</replaceable>
+    </term>
+    <listitem>
+     <para>
+      A list of <replaceable>t</replaceable> type, e.g. <literal>types.listOf
+      int</literal>. Multiple definitions are merged with list concatenation.
+     </para>
+    </listitem>
+   </varlistentry>
+   <varlistentry>
+    <term>
+     <varname>types.attrsOf</varname> <replaceable>t</replaceable>
+    </term>
+    <listitem>
+     <para>
+      An attribute set of where all the values are of
+      <replaceable>t</replaceable> type. Multiple definitions result in the
+      joined attribute set.
+      <note><para>
+       This type is <emphasis>strict</emphasis> in its values, which in turn
+       means attributes cannot depend on other attributes. See <varname>
+       types.lazyAttrsOf</varname> for a lazy version.
+      </para></note>
+     </para>
+    </listitem>
+   </varlistentry>
+   <varlistentry>
+    <term>
+     <varname>types.lazyAttrsOf</varname> <replaceable>t</replaceable>
+    </term>
+    <listitem>
+     <para>
+      An attribute set of where all the values are of
+      <replaceable>t</replaceable> type. Multiple definitions result in the
+      joined attribute set. This is the lazy version of <varname>types.attrsOf
+      </varname>, allowing attributes to depend on each other.
+      <warning><para>
+       This version does not fully support conditional definitions! With an
+       option <varname>foo</varname> of this type and a definition
+       <literal>foo.attr = lib.mkIf false 10</literal>, evaluating
+       <literal>foo ? attr</literal> will return <literal>true</literal>
+       even though it should be false. Accessing the value will then throw
+       an error. For types <replaceable>t</replaceable> that have an
+       <literal>emptyValue</literal> defined, that value will be returned
+       instead of throwing an error. So if the type of <literal>foo.attr</literal>
+       was <literal>lazyAttrsOf (nullOr int)</literal>, <literal>null</literal>
+       would be returned instead for the same <literal>mkIf false</literal> definition.
+      </para></warning>
+     </para>
+    </listitem>
+   </varlistentry>
+   <varlistentry>
+    <term>
+     <varname>types.nullOr</varname> <replaceable>t</replaceable>
+    </term>
+    <listitem>
+     <para>
+      <literal>null</literal> or type <replaceable>t</replaceable>. Multiple
+      definitions are merged according to type <replaceable>t</replaceable>.
+     </para>
+    </listitem>
+   </varlistentry>
+   <varlistentry>
+    <term>
+     <varname>types.uniq</varname> <replaceable>t</replaceable>
+    </term>
+    <listitem>
+     <para>
+      Ensures that type <replaceable>t</replaceable> cannot be merged. It is
+      used to ensure option definitions are declared only once.
+     </para>
+    </listitem>
+   </varlistentry>
+   <varlistentry>
+    <term>
+     <varname>types.either</varname> <replaceable>t1</replaceable> <replaceable>t2</replaceable>
+    </term>
+    <listitem>
+     <para>
+      Type <replaceable>t1</replaceable> or type <replaceable>t2</replaceable>,
+      e.g. <literal>with types; either int str</literal>. Multiple definitions
+      cannot be merged.
+     </para>
+    </listitem>
+   </varlistentry>
+   <varlistentry>
+    <term>
+     <varname>types.oneOf</varname> [ <replaceable>t1</replaceable> <replaceable>t2</replaceable> ... ]
+    </term>
+    <listitem>
+     <para>
+      Type <replaceable>t1</replaceable> or type <replaceable>t2</replaceable> and so forth,
+      e.g. <literal>with types; oneOf [ int str bool ]</literal>. Multiple definitions
+      cannot be merged.
+     </para>
+    </listitem>
+   </varlistentry>
+   <varlistentry>
+    <term>
+     <varname>types.coercedTo</varname> <replaceable>from</replaceable> <replaceable>f</replaceable> <replaceable>to</replaceable>
+    </term>
+    <listitem>
+     <para>
+      Type <replaceable>to</replaceable> or type
+      <replaceable>from</replaceable> which will be coerced to type
+      <replaceable>to</replaceable> using function <replaceable>f</replaceable>
+      which takes an argument of type <replaceable>from</replaceable> and
+      return a value of type <replaceable>to</replaceable>. Can be used to
+      preserve backwards compatibility of an option if its type was changed.
+     </para>
+    </listitem>
+   </varlistentry>
+  </variablelist>
+ </section>
+
+ <section xml:id='section-option-types-submodule'>
+  <title>Submodule</title>
+
+  <para>
+   <literal>submodule</literal> is a very powerful type that defines a set of
+   sub-options that are handled like a separate module.
+  </para>
+
+  <para>
+   It takes a parameter <replaceable>o</replaceable>, that should be a set, or
+   a function returning a set with an <literal>options</literal> key defining
+   the sub-options. Submodule option definitions are type-checked accordingly
+   to the <literal>options</literal> declarations. Of course, you can nest
+   submodule option definitons for even higher modularity.
+  </para>
+
+  <para>
+   The option set can be defined directly
+   (<xref linkend='ex-submodule-direct' />) or as reference
+   (<xref linkend='ex-submodule-reference' />).
+  </para>
+
+  <example xml:id='ex-submodule-direct'>
+   <title>Directly defined submodule</title>
+<screen>
+options.mod = mkOption {
+  description = "submodule example";
+  type = with types; submodule {
+    options = {
+      foo = mkOption {
+        type = int;
+      };
+      bar = mkOption {
+        type = str;
+      };
+    };
+  };
+};</screen>
+  </example>
+
+  <example xml:id='ex-submodule-reference'>
+   <title>Submodule defined as a reference</title>
+<screen>
+let
+  modOptions = {
+    options = {
+      foo = mkOption {
+        type = int;
+      };
+      bar = mkOption {
+        type = int;
+      };
+    };
+  };
+in
+options.mod = mkOption {
+  description = "submodule example";
+  type = with types; submodule modOptions;
+};</screen>
+  </example>
+
+  <para>
+   The <literal>submodule</literal> type is especially interesting when used
+   with composed types like <literal>attrsOf</literal> or
+   <literal>listOf</literal>. When composed with <literal>listOf</literal>
+   (<xref linkend='ex-submodule-listof-declaration' />),
+   <literal>submodule</literal> allows multiple definitions of the submodule
+   option set (<xref linkend='ex-submodule-listof-definition' />).
+  </para>
+
+  <example xml:id='ex-submodule-listof-declaration'>
+   <title>Declaration of a list of submodules</title>
+<screen>
+options.mod = mkOption {
+  description = "submodule example";
+  type = with types; listOf (submodule {
+    options = {
+      foo = mkOption {
+        type = int;
+      };
+      bar = mkOption {
+        type = str;
+      };
+    };
+  });
+};</screen>
+  </example>
+
+  <example xml:id='ex-submodule-listof-definition'>
+   <title>Definition of a list of submodules</title>
+<screen>
+config.mod = [
+  { foo = 1; bar = "one"; }
+  { foo = 2; bar = "two"; }
+];</screen>
+  </example>
+
+  <para>
+   When composed with <literal>attrsOf</literal>
+   (<xref linkend='ex-submodule-attrsof-declaration' />),
+   <literal>submodule</literal> allows multiple named definitions of the
+   submodule option set (<xref linkend='ex-submodule-attrsof-definition' />).
+  </para>
+
+  <example xml:id='ex-submodule-attrsof-declaration'>
+   <title>Declaration of attribute sets of submodules</title>
+<screen>
+options.mod = mkOption {
+  description = "submodule example";
+  type = with types; attrsOf (submodule {
+    options = {
+      foo = mkOption {
+        type = int;
+      };
+      bar = mkOption {
+        type = str;
+      };
+    };
+  });
+};</screen>
+  </example>
+
+  <example xml:id='ex-submodule-attrsof-definition'>
+   <title>Declaration of attribute sets of submodules</title>
+<screen>
+config.mod.one = { foo = 1; bar = "one"; };
+config.mod.two = { foo = 2; bar = "two"; };</screen>
+  </example>
+ </section>
+
+ <section xml:id="sec-option-types-extending">
+  <title>Extending types</title>
+
+  <para>
+   Types are mainly characterized by their <literal>check</literal> and
+   <literal>merge</literal> functions.
+  </para>
+
+  <variablelist>
+   <varlistentry>
+    <term>
+     <varname>check</varname>
+    </term>
+    <listitem>
+     <para>
+      The function to type check the value. Takes a value as parameter and
+      return a boolean. It is possible to extend a type check with the
+      <literal>addCheck</literal> function
+      (<xref
+          linkend='ex-extending-type-check-1' />), or to fully
+      override the check function
+      (<xref linkend='ex-extending-type-check-2' />).
+     </para>
+     <example xml:id='ex-extending-type-check-1'>
+      <title>Adding a type check</title>
+<screen>
+byte = mkOption {
+  description = "An integer between 0 and 255.";
+  type = types.addCheck types.int (x: x &gt;= 0 &amp;&amp; x &lt;= 255);
+};</screen>
+     </example>
+     <example xml:id='ex-extending-type-check-2'>
+      <title>Overriding a type check</title>
+<screen>
+nixThings = mkOption {
+  description = "words that start with 'nix'";
+  type = types.str // {
+    check = (x: lib.hasPrefix "nix" x)
+  };
+};</screen>
+     </example>
+    </listitem>
+   </varlistentry>
+   <varlistentry>
+    <term>
+     <varname>merge</varname>
+    </term>
+    <listitem>
+     <para>
+      Function to merge the options values when multiple values are set. The
+      function takes two parameters, <literal>loc</literal> the option path as
+      a list of strings, and <literal>defs</literal> the list of defined values
+      as a list. It is possible to override a type merge function for custom
+      needs.
+     </para>
+    </listitem>
+   </varlistentry>
+  </variablelist>
+ </section>
+
+ <section xml:id="sec-option-types-custom">
+  <title>Custom Types</title>
+
+  <para>
+   Custom types can be created with the <literal>mkOptionType</literal>
+   function. As type creation includes some more complex topics such as
+   submodule handling, it is recommended to get familiar with
+   <filename
+  xlink:href="https://github.com/NixOS/nixpkgs/blob/master/lib/types.nix">types.nix</filename>
+   code before creating a new type.
+  </para>
+
+  <para>
+   The only required parameter is <literal>name</literal>.
+  </para>
+
+  <variablelist>
+   <varlistentry>
+    <term>
+     <varname>name</varname>
+    </term>
+    <listitem>
+     <para>
+      A string representation of the type function name.
+     </para>
+    </listitem>
+   </varlistentry>
+   <varlistentry>
+    <term>
+     <varname>definition</varname>
+    </term>
+    <listitem>
+     <para>
+      Description of the type used in documentation. Give information of the
+      type and any of its arguments.
+     </para>
+    </listitem>
+   </varlistentry>
+   <varlistentry>
+    <term>
+     <varname>check</varname>
+    </term>
+    <listitem>
+     <para>
+      A function to type check the definition value. Takes the definition value
+      as a parameter and returns a boolean indicating the type check result,
+      <literal>true</literal> for success and <literal>false</literal> for
+      failure.
+     </para>
+    </listitem>
+   </varlistentry>
+   <varlistentry>
+    <term>
+     <varname>merge</varname>
+    </term>
+    <listitem>
+     <para>
+      A function to merge multiple definitions values. Takes two parameters:
+     </para>
+     <variablelist>
+      <varlistentry>
+       <term>
+        <replaceable>loc</replaceable>
+       </term>
+       <listitem>
+        <para>
+         The option path as a list of strings, e.g. <literal>["boot" "loader
+         "grub" "enable"]</literal>.
+        </para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term>
+        <replaceable>defs</replaceable>
+       </term>
+       <listitem>
+        <para>
+         The list of sets of defined <literal>value</literal> and
+         <literal>file</literal> where the value was defined, e.g. <literal>[ {
+         file = "/foo.nix"; value = 1; } { file = "/bar.nix"; value = 2 }
+         ]</literal>. The <literal>merge</literal> function should return the
+         merged value or throw an error in case the values are impossible or
+         not meant to be merged.
+        </para>
+       </listitem>
+      </varlistentry>
+     </variablelist>
+    </listitem>
+   </varlistentry>
+   <varlistentry>
+    <term>
+     <varname>getSubOptions</varname>
+    </term>
+    <listitem>
+     <para>
+      For composed types that can take a submodule as type parameter, this
+      function generate sub-options documentation. It takes the current option
+      prefix as a list and return the set of sub-options. Usually defined in a
+      recursive manner by adding a term to the prefix, e.g. <literal>prefix:
+      elemType.getSubOptions (prefix ++
+      [<replaceable>"prefix"</replaceable>])</literal> where
+      <replaceable>"prefix"</replaceable> is the newly added prefix.
+     </para>
+    </listitem>
+   </varlistentry>
+   <varlistentry>
+    <term>
+     <varname>getSubModules</varname>
+    </term>
+    <listitem>
+     <para>
+      For composed types that can take a submodule as type parameter, this
+      function should return the type parameters submodules. If the type
+      parameter is called <literal>elemType</literal>, the function should just
+      recursively look into submodules by returning
+      <literal>elemType.getSubModules;</literal>.
+     </para>
+    </listitem>
+   </varlistentry>
+   <varlistentry>
+    <term>
+     <varname>substSubModules</varname>
+    </term>
+    <listitem>
+     <para>
+      For composed types that can take a submodule as type parameter, this
+      function can be used to substitute the parameter of a submodule type. It
+      takes a module as parameter and return the type with the submodule
+      options substituted. It is usually defined as a type function call with a
+      recursive call to <literal>substSubModules</literal>, e.g for a type
+      <literal>composedType</literal> that take an <literal>elemtype</literal>
+      type parameter, this function should be defined as <literal>m:
+      composedType (elemType.substSubModules m)</literal>.
+     </para>
+    </listitem>
+   </varlistentry>
+   <varlistentry>
+    <term>
+     <varname>typeMerge</varname>
+    </term>
+    <listitem>
+     <para>
+      A function to merge multiple type declarations. Takes the type to merge
+      <literal>functor</literal> as parameter. A <literal>null</literal> return
+      value means that type cannot be merged.
+     </para>
+     <variablelist>
+      <varlistentry>
+       <term>
+        <replaceable>f</replaceable>
+       </term>
+       <listitem>
+        <para>
+         The type to merge <literal>functor</literal>.
+        </para>
+       </listitem>
+      </varlistentry>
+     </variablelist>
+     <para>
+      Note: There is a generic <literal>defaultTypeMerge</literal> that work
+      with most of value and composed types.
+     </para>
+    </listitem>
+   </varlistentry>
+   <varlistentry>
+    <term>
+     <varname>functor</varname>
+    </term>
+    <listitem>
+     <para>
+      An attribute set representing the type. It is used for type operations
+      and has the following keys:
+     </para>
+     <variablelist>
+      <varlistentry>
+       <term>
+        <varname>type</varname>
+       </term>
+       <listitem>
+        <para>
+         The type function.
+        </para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term>
+        <varname>wrapped</varname>
+       </term>
+       <listitem>
+        <para>
+         Holds the type parameter for composed types.
+        </para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term>
+        <varname>payload</varname>
+       </term>
+       <listitem>
+        <para>
+         Holds the value parameter for value types. The types that have a
+         <literal>payload</literal> are the <literal>enum</literal>,
+         <literal>separatedString</literal> and <literal>submodule</literal>
+         types.
+        </para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term>
+        <varname>binOp</varname>
+       </term>
+       <listitem>
+        <para>
+         A binary operation that can merge the payloads of two same types.
+         Defined as a function that take two payloads as parameters and return
+         the payloads merged.
+        </para>
+       </listitem>
+      </varlistentry>
+     </variablelist>
+    </listitem>
+   </varlistentry>
+  </variablelist>
+ </section>
+</section>
diff --git a/nixpkgs/nixos/doc/manual/development/releases.xml b/nixpkgs/nixos/doc/manual/development/releases.xml
new file mode 100755
index 000000000000..cd68a428a6fb
--- /dev/null
+++ b/nixpkgs/nixos/doc/manual/development/releases.xml
@@ -0,0 +1,366 @@
+<chapter 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="ch-releases">
+ <title>Releases</title>
+ <section xml:id="release-process">
+  <title>Release process</title>
+
+  <para>
+   Going through an example of releasing NixOS 19.09:
+  </para>
+
+  <section xml:id="one-month-before-the-beta">
+   <title>One month before the beta</title>
+
+   <itemizedlist>
+    <listitem>
+     <para>
+      Create an announcement on <link xlink:href="https://discourse.nixos.org">Discourse</link> as a warning about upcoming beta <quote>feature freeze</quote> in a month. <link xlink:href="https://discourse.nixos.org/t/nixos-19-09-feature-freeze/3707">See this post as an example</link>.
+     </para>
+    </listitem>
+    <listitem>
+     <para>
+      Discuss with Eelco Dolstra and the community (via IRC, ML) about what will reach the deadline. Any issue or Pull Request targeting the release should be included in the release milestone.
+     </para>
+    </listitem>
+    <listitem>
+     <para>
+      Remove attributes that we know we will not be able to support, especially if there is a stable alternative. E.g. Check that our Linux kernels’ <link xlink:href="https://www.kernel.org/category/releases.html">projected end-of-life</link> are after our release projected end-of-life.
+     </para>
+    </listitem>
+   </itemizedlist>
+  </section>
+
+  <section xml:id="at-beta-release-time">
+   <title>At beta release time</title>
+
+   <orderedlist>
+    <listitem>
+     <para>
+      From the master branch run:
+     </para>
+<programlisting>
+git checkout -b release-19.09
+</programlisting>
+    </listitem>
+    <listitem>
+     <para>
+      <link xlink:href="https://github.com/NixOS/nixpkgs/commit/10e61bf5be57736035ec7a804cb0bf3d083bf2cf#diff-9c798092bac0caeb5c52d509be0ca263R69">Bump the <literal>system.defaultChannel</literal> attribute in <literal>nixos/modules/misc/version.nix</literal></link>
+     </para>
+    </listitem>
+    <listitem>
+     <para>
+      <link xlink:href="https://github.com/NixOS/nixpkgs/commit/10e61bf5be57736035ec7a804cb0bf3d083bf2cf#diff-831e8d9748240fb23e6734fdc2a6d16eR15">Update <literal>versionSuffix</literal> in <literal>nixos/release.nix</literal></link>
+     </para>
+    </listitem>
+   </orderedlist>
+
+   <para>
+    To get the commit count, use the following command:
+   </para>
+
+<programlisting>
+git rev-list --count release-19.09
+</programlisting>
+
+   <orderedlist>
+    <listitem>
+     <para>
+      Edit changelog at <literal>nixos/doc/manual/release-notes/rl-1909.xml</literal>.
+     </para>
+     <itemizedlist>
+      <listitem>
+       <para>
+        Get all new NixOS modules:
+       </para>
+<programlisting>
+git diff release-19.03..release-19.09 nixos/modules/module-list.nix | grep ^+
+</programlisting>
+      </listitem>
+      <listitem>
+       <para>
+        Note systemd, kernel, glibc, desktop environment, and Nix upgrades.
+       </para>
+      </listitem>
+     </itemizedlist>
+    </listitem>
+    <listitem>
+     <para>
+      Tag the release:
+     </para>
+<programlisting>
+git tag --annotate --message="Release 19.09-beta" 19.09-beta
+git push upstream 19.09-beta
+</programlisting>
+    </listitem>
+    <listitem>
+     <para>
+      <link xlink:href="https://github.com/NixOS/nixpkgs/commit/01268fda85b7eee4e462c873d8654f975067731f#diff-2bc0e46110b507d6d5a344264ef15adaR1">On the <literal>master</literal> branch, increment the <literal>.version</literal> file</link>
+     </para>
+<programlisting>
+echo -n "20.03" > .version
+</programlisting>
+    </listitem>
+    <listitem>
+     <para>
+      <link xlink:href="https://github.com/NixOS/nixpkgs/commit/01268fda85b7eee4e462c873d8654f975067731f#diff-03f3d41b68f62079c55001f1a1c55c1dR137">Update <literal>codeName</literal> in <literal>lib/trivial.nix</literal></link> This will be the name for the next release.
+     </para>
+    </listitem>
+    <listitem>
+     <para>
+      <link xlink:href="https://github.com/NixOS/nixpkgs/commit/01268fda85b7eee4e462c873d8654f975067731f#diff-e7ee5ff686cdcc513ca089d6e5682587R11">Create a new release notes file for the upcoming release + 1</link>, in our case this is <literal>rl-2003.xml</literal>.
+     </para>
+    </listitem>
+    <listitem>
+     <para>
+      Contact the infrastructure team to create the necessary Hydra Jobsets.
+     </para>
+    </listitem>
+    <listitem>
+     <para>
+      <link xlink:href="https://github.com/NixOS/nixos-org-configurations/blob/master/channels.nix">Create a channel at https://nixos.org/channels by creating a PR to nixos-org-configurations, changing <literal>channels.nix</literal></link>
+     </para>
+    </listitem>
+    <listitem>
+     <para>
+      Get all Hydra jobsets for the release to have their first evaluation.
+     </para>
+    </listitem>
+    <listitem>
+     <para>
+      <link xlink:href="https://github.com/NixOS/nixpkgs/issues/13559">Create an issue for tracking Zero Hydra Failures progress. ZHF is an effort to get build failures down to zero.</link>
+     </para>
+    </listitem>
+   </orderedlist>
+  </section>
+
+  <section xml:id="during-beta">
+   <title>During Beta</title>
+
+   <itemizedlist>
+    <listitem>
+     <para>
+      Monitor the master branch for bugfixes and minor updates and cherry-pick them to the release branch.
+     </para>
+    </listitem>
+   </itemizedlist>
+  </section>
+
+  <section xml:id="before-the-final-release">
+   <title>Before the final release</title>
+
+   <itemizedlist>
+    <listitem>
+     <para>
+      Re-check that the release notes are complete.
+     </para>
+    </listitem>
+    <listitem>
+     <para>
+      Release Nix (currently only Eelco Dolstra can do that). <link xlink:href="https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/installer/tools/nix-fallback-paths.nix">Make sure fallback is updated.</link>
+     </para>
+    </listitem>
+    <listitem>
+     <para>
+      <link xlink:href="https://github.com/NixOS/nixpkgs/commit/40fd9ae3ac8048758abdcfc7d28a78b5f22fe97e">Update README.md with new stable NixOS version information.</link>
+     </para>
+    </listitem>
+    <listitem>
+     <para>
+      Change <literal>stableBranch</literal> to <literal>true</literal> in Hydra and wait for the channel to update.
+     </para>
+    </listitem>
+   </itemizedlist>
+  </section>
+
+  <section xml:id="at-final-release-time">
+   <title>At final release time</title>
+
+   <orderedlist>
+    <listitem>
+     <para>
+      Update <xref linkend="sec-upgrading" /> section of the manual to match new stable release version.
+     </para>
+    </listitem>
+    <listitem>
+     <para>
+      Update <literal>rl-1909.xml</literal> with the release date.
+     </para>
+    </listitem>
+    <listitem>
+     <para>
+      Tag the final release
+     </para>
+<programlisting>
+git tag --annotate --message="Release 19.09" 19.09
+git push upstream 19.09
+</programlisting>
+    </listitem>
+    <listitem>
+     <para>
+      Update <link xlink:href="https://github.com/NixOS/nixos-homepage">nixos-homepage</link> for the release.
+     </para>
+     <orderedlist>
+      <listitem>
+       <para>
+        <link xlink:href="https://github.com/NixOS/nixos-homepage/blob/47ac3571c4d71e841fd4e6c6e1872e762b9c4942/Makefile#L1">Update <literal>NIXOS_SERIES</literal> in the <literal>Makefile</literal></link>.
+       </para>
+      </listitem>
+      <listitem>
+       <para>
+        <link xlink:href="https://github.com/NixOS/nixos-homepage/blob/47ac3571c4d71e841fd4e6c6e1872e762b9c4942/nixos-release.tt#L1">Update <literal>nixos-release.tt</literal> with the new NixOS version</link>.
+       </para>
+      </listitem>
+      <listitem>
+       <para>
+        <link xlink:href="https://github.com/NixOS/nixos-homepage/blob/47ac3571c4d71e841fd4e6c6e1872e762b9c4942/flake.nix#L10">Update the <literal>flake.nix</literal> input <literal>released-nixpkgs</literal> to 19.09</link>.
+       </para>
+      </listitem>
+      <listitem>
+       <para>
+        Run <literal>./update.sh</literal> (this updates flake.lock to updated channel).
+       </para>
+      </listitem>
+      <listitem>
+       <para>
+        <link xlink:href="https://github.com/NixOS/nixos-homepage/blob/a5626c71c03a2dd69086564e56f1a230a2bb177a/logo/nixos-logo-19.09-loris-lores.png">Add a compressed version of the NixOS logo for 19.09</link>.
+       </para>
+      </listitem>
+      <listitem>
+       <para>
+        <link xlink:href="https://github.com/NixOS/nixos-homepage/commit/a5626c71c03a2dd69086564e56f1a230a2bb177a#diff-9cdc6434d3e4fd93a6e5bb0a531a7c71R5">Compose a news item for the website RSS feed</link>.
+       </para>
+      </listitem>
+     </orderedlist>
+    </listitem>
+    <listitem>
+     <para>
+      Create a new topic on <link xlink:href="https://discourse.nixos.org/">the Discourse instance</link> to announce the release.
+     </para>
+    </listitem>
+   </orderedlist>
+
+   <para>
+    You should include the following information:
+   </para>
+
+   <itemizedlist>
+    <listitem>
+     <para>
+      Number of commits for the release:
+     </para>
+<programlisting>
+bash git log release-19.03..release-19.09 --format=%an | wc -l
+</programlisting>
+    </listitem>
+    <listitem>
+     <para>
+      Commits by contributor:
+     </para>
+<programlisting>
+git shortlog --summary --numbered release-19.03..release-19.09
+</programlisting>
+    </listitem>
+   </itemizedlist>
+
+   <para>
+    Best to check how the previous post was formulated to see what needs to be included.
+   </para>
+  </section>
+ </section>
+ <section xml:id="release-management-team">
+  <title>Release Management Team</title>
+
+  <para>
+   For each release there are two release managers. After each release the release manager having managed two releases steps down and the release management team of the last release appoints a new release manager.
+  </para>
+
+  <para>
+   This makes sure a release management team always consists of one release manager who already has managed one release and one release manager being introduced to their role, making it easier to pass on knowledge and experience.
+  </para>
+
+  <para>
+   Release managers for the current NixOS release are tracked by GitHub team <link xlink:href="https://github.com/orgs/NixOS/teams/nixos-release-managers/members"><literal>@NixOS/nixos-release-managers</literal></link>.
+  </para>
+
+  <para>
+   A release manager’s role and responsibilities are:
+  </para>
+
+  <itemizedlist>
+   <listitem>
+    <para>
+     manage the release process
+    </para>
+   </listitem>
+   <listitem>
+    <para>
+     start discussions about features and changes for a given release
+    </para>
+   </listitem>
+   <listitem>
+    <para>
+     create a roadmap
+    </para>
+   </listitem>
+   <listitem>
+    <para>
+     release in cooperation with Eelco Dolstra
+    </para>
+   </listitem>
+   <listitem>
+    <para>
+     decide which bug fixes, features, etc… get backported after a release
+    </para>
+   </listitem>
+  </itemizedlist>
+ </section>
+ <section xml:id="release-schedule">
+  <title>Release schedule</title>
+
+  <informaltable>
+   <tgroup cols="2">
+    <colspec align="left" />
+    <colspec align="left" />
+    <thead>
+     <row>
+      <entry>
+            Date
+          </entry>
+      <entry>
+            Event
+          </entry>
+     </row>
+    </thead>
+    <tbody>
+     <row>
+      <entry>
+            2016-07-25
+          </entry>
+      <entry>
+            Send email to nix-dev about upcoming branch-off
+          </entry>
+     </row>
+     <row>
+      <entry>
+            2016-09-01
+          </entry>
+      <entry><literal>release-16.09</literal> branch and corresponding jobsets are created,
+            change freeze
+          </entry>
+     </row>
+     <row>
+      <entry>
+            2016-09-30
+          </entry>
+      <entry>
+            NixOS 16.09 released
+          </entry>
+     </row>
+    </tbody>
+   </tgroup>
+  </informaltable>
+ </section>
+</chapter>
diff --git a/nixpkgs/nixos/doc/manual/development/replace-modules.xml b/nixpkgs/nixos/doc/manual/development/replace-modules.xml
new file mode 100644
index 000000000000..9fc5678ca1b3
--- /dev/null
+++ b/nixpkgs/nixos/doc/manual/development/replace-modules.xml
@@ -0,0 +1,79 @@
+<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-replace-modules">
+ <title>Replace Modules</title>
+
+ <para>
+  Modules that are imported can also be disabled. The option declarations,
+  config implementation and the imports of a disabled module will be ignored, allowing another
+  to take it's place. This can be used to import a set of modules from another
+  channel while keeping the rest of the system on a stable release.
+ </para>
+
+ <para>
+  <literal>disabledModules</literal> is a top level attribute like
+  <literal>imports</literal>, <literal>options</literal> and
+  <literal>config</literal>. It contains a list of modules that will be
+  disabled. This can either be the full path to the module or a string with the
+  filename relative to the modules path (eg. &lt;nixpkgs/nixos/modules&gt; for
+  nixos).
+ </para>
+
+ <para>
+  This example will replace the existing postgresql module with the version
+  defined in the nixos-unstable channel while keeping the rest of the modules
+  and packages from the original nixos channel. This only overrides the module
+  definition, this won't use postgresql from nixos-unstable unless explicitly
+  configured to do so.
+ </para>
+
+<programlisting>
+{ config, lib, pkgs, ... }:
+
+{
+  disabledModules = [ "services/databases/postgresql.nix" ];
+
+  imports =
+    [ # Use postgresql service from nixos-unstable channel.
+      # sudo nix-channel --add https://nixos.org/channels/nixos-unstable nixos-unstable
+      &lt;nixos-unstable/nixos/modules/services/databases/postgresql.nix&gt;
+    ];
+
+  services.postgresql.enable = true;
+}
+</programlisting>
+
+ <para>
+  This example shows how to define a custom module as a replacement for an
+  existing module. Importing this module will disable the original module
+  without having to know it's implementation details.
+ </para>
+
+<programlisting>
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.programs.man;
+in
+
+{
+  disabledModules = [ "services/programs/man.nix" ];
+
+  options = {
+    programs.man.enable = mkOption {
+      type = types.bool;
+      default = true;
+      description = "Whether to enable manual pages.";
+    };
+  };
+
+  config = mkIf cfg.enabled {
+    warnings = [ "disabled manpages for production deployments." ];
+  };
+}
+</programlisting>
+</section>
diff --git a/nixpkgs/nixos/doc/manual/development/running-nixos-tests-interactively.xml b/nixpkgs/nixos/doc/manual/development/running-nixos-tests-interactively.xml
new file mode 100644
index 000000000000..a6044d5f89e8
--- /dev/null
+++ b/nixpkgs/nixos/doc/manual/development/running-nixos-tests-interactively.xml
@@ -0,0 +1,49 @@
+<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-running-nixos-tests-interactively">
+ <title>Running Tests interactively</title>
+
+ <para>
+  The test itself can be run interactively. This is particularly useful when
+  developing or debugging a test:
+<screen>
+<prompt>$ </prompt>nix-build nixos/tests/login.nix -A driverInteractive
+<prompt>$ </prompt>./result/bin/nixos-test-driver
+starting VDE switch for network 1
+<prompt>&gt;</prompt>
+</screen>
+  You can then take any Python statement, e.g.
+<screen>
+<prompt>&gt;</prompt> start_all()
+<prompt>&gt;</prompt> test_script()
+<prompt>&gt;</prompt> machine.succeed("touch /tmp/foo")
+<prompt>&gt;</prompt> print(machine.succeed("pwd")) # Show stdout of command
+</screen>
+  The function <command>test_script</command> executes the entire test script
+  and drops you back into the test driver command line upon its completion.
+  This allows you to inspect the state of the VMs after the test (e.g. to debug
+  the test script).
+ </para>
+
+ <para>
+  To just start and experiment with the VMs, run:
+<screen>
+<prompt>$ </prompt>nix-build nixos/tests/login.nix -A driverInteractive
+<prompt>$ </prompt>./result/bin/nixos-run-vms
+</screen>
+  The script <command>nixos-run-vms</command> starts the virtual machines
+  defined by test.
+ </para>
+
+ <para>
+   You can re-use the VM states coming from a previous run
+   by setting the <command>--keep-vm-state</command> flag.
+<screen>
+<prompt>$ </prompt>./result/bin/nixos-run-vms --keep-vm-state
+</screen>
+  The machine state is stored in the
+  <filename>$TMPDIR/vm-state-</filename><varname>machinename</varname> directory.
+ </para>
+</section>
diff --git a/nixpkgs/nixos/doc/manual/development/running-nixos-tests.xml b/nixpkgs/nixos/doc/manual/development/running-nixos-tests.xml
new file mode 100644
index 000000000000..e9257c907daf
--- /dev/null
+++ b/nixpkgs/nixos/doc/manual/development/running-nixos-tests.xml
@@ -0,0 +1,36 @@
+<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-running-nixos-tests">
+ <title>Running Tests</title>
+
+ <para>
+  You can run tests using <command>nix-build</command>. For example, to run the
+  test
+  <filename
+xlink:href="https://github.com/NixOS/nixpkgs/blob/master/nixos/tests/login.nix">login.nix</filename>,
+  you just do:
+<screen>
+<prompt>$ </prompt>nix-build '&lt;nixpkgs/nixos/tests/login.nix>'
+</screen>
+  or, if you don’t want to rely on <envar>NIX_PATH</envar>:
+<screen>
+<prompt>$ </prompt>cd /my/nixpkgs/nixos/tests
+<prompt>$ </prompt>nix-build login.nix
+…
+running the VM test script
+machine: QEMU running (pid 8841)
+…
+6 out of 6 tests succeeded
+</screen>
+  After building/downloading all required dependencies, this will perform a
+  build that starts a QEMU/KVM virtual machine containing a NixOS system. The
+  virtual machine mounts the Nix store of the host; this makes VM creation very
+  fast, as no disk image needs to be created. Afterwards, you can view a
+  pretty-printed log of the test:
+<screen>
+<prompt>$ </prompt>firefox result/log.html
+</screen>
+ </para>
+</section>
diff --git a/nixpkgs/nixos/doc/manual/development/settings-options.xml b/nixpkgs/nixos/doc/manual/development/settings-options.xml
new file mode 100644
index 000000000000..c99c3af92f89
--- /dev/null
+++ b/nixpkgs/nixos/doc/manual/development/settings-options.xml
@@ -0,0 +1,216 @@
+<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-settings-options">
+ <title>Options for Program Settings</title>
+
+ <para>
+   Many programs have configuration files where program-specific settings can be declared. File formats can be separated into two categories:
+   <itemizedlist>
+     <listitem>
+       <para>
+         Nix-representable ones: These can trivially be mapped to a subset of Nix syntax. E.g. JSON is an example, since its values like <literal>{"foo":{"bar":10}}</literal> can be mapped directly to Nix: <literal>{ foo = { bar = 10; }; }</literal>. Other examples are INI, YAML and TOML. The following section explains the convention for these settings.
+       </para>
+     </listitem>
+     <listitem>
+       <para>
+         Non-nix-representable ones: These can't be trivially mapped to a subset of Nix syntax. Most generic programming languages are in this group, e.g. bash, since the statement <literal>if true; then echo hi; fi</literal> doesn't have a trivial representation in Nix.
+       </para>
+       <para>
+         Currently there are no fixed conventions for these, but it is common to have a <literal>configFile</literal> option for setting the configuration file path directly. The default value of <literal>configFile</literal> can be an auto-generated file, with convenient options for controlling the contents. For example an option of type <literal>attrsOf str</literal> can be used for representing environment variables which generates a section like <literal>export FOO="foo"</literal>. Often it can also be useful to also include an <literal>extraConfig</literal> option of type <literal>lines</literal> to allow arbitrary text after the autogenerated part of the file.
+       </para>
+     </listitem>
+   </itemizedlist>
+ </para>
+ <section xml:id="sec-settings-nix-representable">
+   <title>Nix-representable Formats (JSON, YAML, TOML, INI, ...)</title>
+   <para>
+     By convention, formats like this are handled with a generic <literal>settings</literal> option, representing the full program configuration as a Nix value. The type of this option should represent the format. The most common formats have a predefined type and string generator already declared under <literal>pkgs.formats</literal>:
+     <variablelist>
+       <varlistentry>
+         <term>
+           <varname>pkgs.formats.json</varname> { }
+         </term>
+         <listitem>
+           <para>
+             A function taking an empty attribute set (for future extensibility) and returning a set with JSON-specific attributes <varname>type</varname> and <varname>generate</varname> as specified <link linkend='pkgs-formats-result'>below</link>.
+           </para>
+         </listitem>
+       </varlistentry>
+       <varlistentry>
+         <term>
+           <varname>pkgs.formats.yaml</varname> { }
+         </term>
+         <listitem>
+           <para>
+             A function taking an empty attribute set (for future extensibility) and returning a set with YAML-specific attributes <varname>type</varname> and <varname>generate</varname> as specified <link linkend='pkgs-formats-result'>below</link>.
+           </para>
+         </listitem>
+       </varlistentry>
+       <varlistentry>
+         <term>
+           <varname>pkgs.formats.ini</varname> { <replaceable>listsAsDuplicateKeys</replaceable> ? false, ... }
+         </term>
+         <listitem>
+           <para>
+             A function taking an attribute set with values
+             <variablelist>
+               <varlistentry>
+                 <term>
+                   <varname>listsAsDuplicateKeys</varname>
+                 </term>
+                 <listitem>
+                   <para>
+                     A boolean for controlling whether list values can be used to represent duplicate INI keys
+                   </para>
+                 </listitem>
+               </varlistentry>
+             </variablelist>
+            It returns a set with INI-specific attributes <varname>type</varname> and <varname>generate</varname> as specified <link linkend='pkgs-formats-result'>below</link>.
+           </para>
+         </listitem>
+       </varlistentry>
+       <varlistentry>
+         <term>
+           <varname>pkgs.formats.toml</varname> { }
+         </term>
+         <listitem>
+           <para>
+             A function taking an empty attribute set (for future extensibility) and returning a set with TOML-specific attributes <varname>type</varname> and <varname>generate</varname> as specified <link linkend='pkgs-formats-result'>below</link>.
+           </para>
+         </listitem>
+       </varlistentry>
+     </variablelist>
+
+   </para>
+   <para xml:id="pkgs-formats-result">
+     These functions all return an attribute set with these values:
+    <variablelist>
+      <varlistentry>
+        <term>
+          <varname>type</varname>
+        </term>
+        <listitem>
+          <para>
+            A module system type representing a value of the format
+          </para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term>
+          <varname>generate</varname> <replaceable>filename</replaceable> <replaceable>jsonValue</replaceable>
+        </term>
+        <listitem>
+          <para>
+           A function that can render a value of the format to a file. Returns a file path.
+           <note>
+            <para>
+             This function puts the value contents in the Nix store. So this should be avoided for secrets.
+            </para>
+           </note>
+          </para>
+        </listitem>
+      </varlistentry>
+    </variablelist>
+   </para>
+   <example xml:id="ex-settings-nix-representable">
+     <title>Module with conventional <literal>settings</literal> option</title>
+     <para>
+       The following shows a module for an example program that uses a JSON configuration file. It demonstrates how above values can be used, along with some other related best practices. See the comments for explanations.
+     </para>
+<programlisting>
+{ options, config, lib, pkgs, ... }:
+let
+  cfg = config.services.foo;
+  # Define the settings format used for this program
+  settingsFormat = pkgs.formats.json {};
+in {
+
+  options.services.foo = {
+    enable = lib.mkEnableOption "foo service";
+
+    settings = lib.mkOption {
+      # Setting this type allows for correct merging behavior
+      type = settingsFormat.type;
+      default = {};
+      description = ''
+        Configuration for foo, see
+        &lt;link xlink:href="https://example.com/docs/foo"/&gt;
+        for supported settings.
+      '';
+    };
+  };
+
+  config = lib.mkIf cfg.enable {
+    # We can assign some default settings here to make the service work by just
+    # enabling it. We use `mkDefault` for values that can be changed without
+    # problems
+    services.foo.settings = {
+      # Fails at runtime without any value set
+      log_level = lib.mkDefault "WARN";
+
+      # We assume systemd's `StateDirectory` is used, so we require this value,
+      # therefore no mkDefault
+      data_path = "/var/lib/foo";
+
+      # Since we use this to create a user we need to know the default value at
+      # eval time
+      user = lib.mkDefault "foo";
+    };
+
+    environment.etc."foo.json".source =
+      # The formats generator function takes a filename and the Nix value
+      # representing the format value and produces a filepath with that value
+      # rendered in the format
+      settingsFormat.generate "foo-config.json" cfg.settings;
+
+    # We know that the `user` attribute exists because we set a default value
+    # for it above, allowing us to use it without worries here
+    users.users.${cfg.settings.user} = {};
+
+    # ...
+  };
+}
+</programlisting>
+   </example>
+   <section xml:id="sec-settings-attrs-options">
+    <title>Option declarations for attributes</title>
+    <para>
+     Some <literal>settings</literal> attributes may deserve some extra care. They may need a different type, default or merging behavior, or they are essential options that should show their documentation in the manual. This can be done using <xref linkend='sec-freeform-modules'/>.
+     <example xml:id="ex-settings-typed-attrs">
+      <title>Declaring a type-checked <literal>settings</literal> attribute</title>
+      <para>
+       We extend above example using freeform modules to declare an option for the port, which will enforce it to be a valid integer and make it show up in the manual.
+      </para>
+<programlisting>
+settings = lib.mkOption {
+  type = lib.types.submodule {
+
+    freeformType = settingsFormat.type;
+
+    # Declare an option for the port such that the type is checked and this option
+    # is shown in the manual.
+    options.port = lib.mkOption {
+      type = lib.types.port;
+      default = 8080;
+      description = ''
+        Which port this service should listen on.
+      '';
+    };
+
+  };
+  default = {};
+  description = ''
+    Configuration for Foo, see
+    &lt;link xlink:href="https://example.com/docs/foo"/&gt;
+    for supported values.
+  '';
+};
+</programlisting>
+     </example>
+    </para>
+   </section>
+ </section>
+
+</section>
diff --git a/nixpkgs/nixos/doc/manual/development/sources.xml b/nixpkgs/nixos/doc/manual/development/sources.xml
new file mode 100644
index 000000000000..b333ccabb420
--- /dev/null
+++ b/nixpkgs/nixos/doc/manual/development/sources.xml
@@ -0,0 +1,85 @@
+<chapter 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-getting-sources">
+ <title>Getting the Sources</title>
+ <para>
+  By default, NixOS’s <command>nixos-rebuild</command> command uses the NixOS
+  and Nixpkgs sources provided by the <literal>nixos</literal> channel (kept in
+  <filename>/nix/var/nix/profiles/per-user/root/channels/nixos</filename>). To
+  modify NixOS, however, you should check out the latest sources from Git. This
+  is as follows:
+<screen>
+<prompt>$ </prompt>git clone https://github.com/NixOS/nixpkgs
+<prompt>$ </prompt>cd nixpkgs
+<prompt>$ </prompt>git remote update origin
+</screen>
+  This will check out the latest Nixpkgs sources to
+  <filename>./nixpkgs</filename> the NixOS sources to
+  <filename>./nixpkgs/nixos</filename>. (The NixOS source tree lives in a
+  subdirectory of the Nixpkgs repository.) The
+  <literal>nixpkgs</literal> repository has branches that correspond
+  to each Nixpkgs/NixOS channel (see <xref linkend="sec-upgrading"/> for more
+  information about channels). Thus, the Git branch
+  <literal>origin/nixos-17.03</literal> will contain the latest built and
+  tested version available in the <literal>nixos-17.03</literal> channel.
+ </para>
+ <para>
+  It’s often inconvenient to develop directly on the master branch, since if
+  somebody has just committed (say) a change to GCC, then the binary cache may
+  not have caught up yet and you’ll have to rebuild everything from source.
+  So you may want to create a local branch based on your current NixOS version:
+<screen>
+<prompt>$ </prompt>nixos-version
+17.09pre104379.6e0b727 (Hummingbird)
+
+<prompt>$ </prompt>git checkout -b local 6e0b727
+</screen>
+  Or, to base your local branch on the latest version available in a NixOS
+  channel:
+<screen>
+<prompt>$ </prompt>git remote update origin
+<prompt>$ </prompt>git checkout -b local origin/nixos-17.03
+</screen>
+  (Replace <literal>nixos-17.03</literal> with the name of the channel you want
+  to use.) You can use <command>git merge</command> or <command>git
+  rebase</command> to keep your local branch in sync with the channel, e.g.
+<screen>
+<prompt>$ </prompt>git remote update origin
+<prompt>$ </prompt>git merge origin/nixos-17.03
+</screen>
+  You can use <command>git cherry-pick</command> to copy commits from your
+  local branch to the upstream branch.
+ </para>
+ <para>
+  If you want to rebuild your system using your (modified) sources, you need to
+  tell <command>nixos-rebuild</command> about them using the
+  <option>-I</option> flag:
+<screen>
+<prompt># </prompt>nixos-rebuild switch -I nixpkgs=<replaceable>/my/sources</replaceable>/nixpkgs
+</screen>
+ </para>
+ <para>
+  If you want <command>nix-env</command> to use the expressions in
+  <replaceable>/my/sources</replaceable>, use <command>nix-env -f
+  <replaceable>/my/sources</replaceable>/nixpkgs</command>, or change the
+  default by adding a symlink in <filename>~/.nix-defexpr</filename>:
+<screen>
+<prompt>$ </prompt>ln -s <replaceable>/my/sources</replaceable>/nixpkgs ~/.nix-defexpr/nixpkgs
+</screen>
+  You may want to delete the symlink
+  <filename>~/.nix-defexpr/channels_root</filename> to prevent root’s NixOS
+  channel from clashing with your own tree (this may break the
+  command-not-found utility though). If you want to go back to the default
+  state, you may just remove the <filename>~/.nix-defexpr</filename> directory
+  completely, log out and log in again and it should have been recreated with a
+  link to the root channels.
+ </para>
+<!-- FIXME: not sure what this means.
+<para>You should not pass the base directory
+<filename><replaceable>/my/sources</replaceable></filename>
+to <command>nix-env</command>, as it will break after interpreting expressions
+in <filename>nixos/</filename> as packages.</para>
+-->
+</chapter>
diff --git a/nixpkgs/nixos/doc/manual/development/testing-installer.xml b/nixpkgs/nixos/doc/manual/development/testing-installer.xml
new file mode 100644
index 000000000000..902f995fbc1b
--- /dev/null
+++ b/nixpkgs/nixos/doc/manual/development/testing-installer.xml
@@ -0,0 +1,22 @@
+<chapter 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="ch-testing-installer">
+ <title>Testing the Installer</title>
+ <para>
+  Building, burning, and booting from an installation CD is rather tedious, so
+  here is a quick way to see if the installer works properly:
+<screen>
+<prompt># </prompt>mount -t tmpfs none /mnt
+<prompt># </prompt>nixos-generate-config --root /mnt
+<prompt>$ </prompt>nix-build '&lt;nixpkgs/nixos>' -A config.system.build.nixos-install
+<prompt># </prompt>./result/bin/nixos-install</screen>
+  To start a login shell in the new NixOS installation in
+  <filename>/mnt</filename>:
+<screen>
+<prompt>$ </prompt>nix-build '&lt;nixpkgs/nixos>' -A config.system.build.nixos-enter
+<prompt># </prompt>./result/bin/nixos-enter
+</screen>
+ </para>
+</chapter>
diff --git a/nixpkgs/nixos/doc/manual/development/writing-documentation.xml b/nixpkgs/nixos/doc/manual/development/writing-documentation.xml
new file mode 100644
index 000000000000..89fab6665616
--- /dev/null
+++ b/nixpkgs/nixos/doc/manual/development/writing-documentation.xml
@@ -0,0 +1,150 @@
+<chapter 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-writing-documentation">
+ <title>Writing NixOS Documentation</title>
+ <para>
+  As NixOS grows, so too does the need for a catalogue and explanation of its
+  extensive functionality. Collecting pertinent information from disparate
+  sources and presenting it in an accessible style would be a worthy
+  contribution to the project.
+ </para>
+ <section xml:id="sec-writing-docs-building-the-manual">
+  <title>Building the Manual</title>
+
+  <para>
+   The DocBook sources of the <xref linkend="book-nixos-manual"/> are in the
+   <link xlink:href="https://github.com/NixOS/nixpkgs/tree/master/nixos/doc/manual"><filename>nixos/doc/manual</filename></link>
+   subdirectory of the Nixpkgs repository.
+  </para>
+
+  <para>
+   You can quickly validate your edits with <command>make</command>:
+  </para>
+
+<screen>
+<prompt>$ </prompt>cd /path/to/nixpkgs/nixos/doc/manual
+<prompt>$ </prompt>nix-shell
+<prompt>nix-shell$ </prompt>make
+</screen>
+
+  <para>
+   Once you are done making modifications to the manual, it's important to
+   build it before committing. You can do that as follows:
+  </para>
+
+<screen>nix-build nixos/release.nix -A manual.x86_64-linux</screen>
+
+  <para>
+   When this command successfully finishes, it will tell you where the manual
+   got generated. The HTML will be accessible through the
+   <filename>result</filename> symlink at
+   <filename>./result/share/doc/nixos/index.html</filename>.
+  </para>
+ </section>
+ <section xml:id="sec-writing-docs-editing-docbook-xml">
+  <title>Editing DocBook XML</title>
+
+  <para>
+   For general information on how to write in DocBook, see
+   <link xlink:href="http://www.docbook.org/tdg5/en/html/docbook.html"> DocBook
+   5: The Definitive Guide</link>.
+  </para>
+
+  <para>
+   Emacs nXML Mode is very helpful for editing DocBook XML because it validates
+   the document as you write, and precisely locates errors. To use it, see
+   <xref linkend="sec-emacs-docbook-xml"/>.
+  </para>
+
+  <para>
+   <link xlink:href="http://pandoc.org">Pandoc</link> can generate DocBook XML
+   from a multitude of formats, which makes a good starting point.
+   <example xml:id="ex-pandoc-xml-conv">
+    <title>Pandoc invocation to convert GitHub-Flavoured MarkDown to DocBook 5 XML</title>
+<screen>pandoc -f markdown_github -t docbook5 docs.md -o my-section.md</screen>
+   </example>
+   Pandoc can also quickly convert a single <filename>section.xml</filename> to
+   HTML, which is helpful when drafting.
+  </para>
+
+  <para>
+   Sometimes writing valid DocBook is simply too difficult. In this case,
+   submit your documentation updates in a
+   <link
+  xlink:href="https://github.com/NixOS/nixpkgs/issues/new">GitHub
+   Issue</link> and someone will handle the conversion to XML for you.
+  </para>
+ </section>
+ <section xml:id="sec-writing-docs-creating-a-topic">
+  <title>Creating a Topic</title>
+
+  <para>
+   You can use an existing topic as a basis for the new topic or create a topic
+   from scratch.
+  </para>
+
+  <para>
+   Keep the following guidelines in mind when you create and add a topic:
+   <itemizedlist>
+    <listitem>
+     <para>
+      The NixOS
+      <link xlink:href="http://www.docbook.org/tdg5/en/html/book.html"><tag>book</tag></link>
+      element is in <filename>nixos/doc/manual/manual.xml</filename>. It
+      includes several
+      <link xlink:href="http://www.docbook.org/tdg5/en/html/book.html"><tag>part</tag>s</link>
+      which are in subdirectories.
+     </para>
+    </listitem>
+    <listitem>
+     <para>
+      Store the topic file in the same directory as the <tag>part</tag> to
+      which it belongs. If your topic is about configuring a NixOS module, then
+      the XML file can be stored alongside the module definition
+      <filename>nix</filename> file.
+     </para>
+    </listitem>
+    <listitem>
+     <para>
+      If you include multiple words in the file name, separate the words with a
+      dash. For example: <filename>ipv6-config.xml</filename>.
+     </para>
+    </listitem>
+    <listitem>
+     <para>
+      Make sure that the <tag>xml:id</tag> value is unique. You can use
+      abbreviations if the ID is too long. For example:
+      <varname>nixos-config</varname>.
+     </para>
+    </listitem>
+    <listitem>
+     <para>
+      Determine whether your topic is a chapter or a section. If you are
+      unsure, open an existing topic file and check whether the main element is
+      chapter or section.
+     </para>
+    </listitem>
+   </itemizedlist>
+  </para>
+ </section>
+ <section xml:id="sec-writing-docs-adding-a-topic">
+  <title>Adding a Topic to the Book</title>
+
+  <para>
+   Open the parent XML file and add an <varname>xi:include</varname> element to
+   the list of chapters with the file name of the topic that you created. If
+   you created a <tag>section</tag>, you add the file to the <tag>chapter</tag>
+   file. If you created a <tag>chapter</tag>, you add the file to the
+   <tag>part</tag> file.
+  </para>
+
+  <para>
+   If the topic is about configuring a NixOS module, it can be automatically
+   included in the manual by using the <varname>meta.doc</varname> attribute.
+   See <xref
+  linkend="sec-meta-attributes"/> for an explanation.
+  </para>
+ </section>
+</chapter>
diff --git a/nixpkgs/nixos/doc/manual/development/writing-modules.xml b/nixpkgs/nixos/doc/manual/development/writing-modules.xml
new file mode 100644
index 000000000000..fad4637f51f0
--- /dev/null
+++ b/nixpkgs/nixos/doc/manual/development/writing-modules.xml
@@ -0,0 +1,191 @@
+<chapter 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-writing-modules">
+ <title>Writing NixOS Modules</title>
+ <para>
+  NixOS has a modular system for declarative configuration. This system
+  combines multiple <emphasis>modules</emphasis> to produce the full system
+  configuration. One of the modules that constitute the configuration is
+  <filename>/etc/nixos/configuration.nix</filename>. Most of the others live in
+  the
+  <link
+xlink:href="https://github.com/NixOS/nixpkgs/tree/master/nixos/modules"><filename>nixos/modules</filename></link>
+  subdirectory of the Nixpkgs tree.
+ </para>
+ <para>
+  Each NixOS module is a file that handles one logical aspect of the
+  configuration, such as a specific kind of hardware, a service, or network
+  settings. A module configuration does not have to handle everything from
+  scratch; it can use the functionality provided by other modules for its
+  implementation. Thus a module can <emphasis>declare</emphasis> options that
+  can be used by other modules, and conversely can <emphasis>define</emphasis>
+  options provided by other modules in its own implementation. For example, the
+  module
+  <link
+xlink:href="https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/security/pam.nix"><filename>pam.nix</filename></link>
+  declares the option <option>security.pam.services</option> that allows other
+  modules (e.g.
+  <link
+xlink:href="https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/services/networking/ssh/sshd.nix"><filename>sshd.nix</filename></link>)
+  to define PAM services; and it defines the option
+  <option>environment.etc</option> (declared by
+  <link
+xlink:href="https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/system/etc/etc.nix"><filename>etc.nix</filename></link>)
+  to cause files to be created in <filename>/etc/pam.d</filename>.
+ </para>
+ <para xml:id="para-module-syn">
+  In <xref
+linkend="sec-configuration-syntax"/>, we saw the following structure
+  of NixOS modules:
+<programlisting>
+{ config, pkgs, ... }:
+
+{ <replaceable>option definitions</replaceable>
+}
+</programlisting>
+  This is actually an <emphasis>abbreviated</emphasis> form of module that only
+  defines options, but does not declare any. The structure of full NixOS
+  modules is shown in <xref linkend='ex-module-syntax' />.
+ </para>
+ <example xml:id='ex-module-syntax'>
+  <title>Structure of NixOS Modules</title>
+<programlisting>
+{ config, pkgs, ... }: <co xml:id='module-syntax-1' />
+
+{
+  imports =
+    [ <replaceable>paths of other modules</replaceable> <co xml:id='module-syntax-2' />
+    ];
+
+  options = {
+    <replaceable>option declarations</replaceable> <co xml:id='module-syntax-3' />
+  };
+
+  config = {
+    <replaceable>option definitions</replaceable> <co xml:id='module-syntax-4' />
+  };
+}</programlisting>
+ </example>
+ <para>
+  The meaning of each part is as follows.
+  <calloutlist>
+   <callout arearefs='module-syntax-1'>
+    <para>
+     This line makes the current Nix expression a function. The variable
+     <varname>pkgs</varname> contains Nixpkgs (by default, it takes the
+     <varname>nixpkgs</varname> entry of <envar>NIX_PATH</envar>, see the <link
+     xlink:href="https://nixos.org/manual/nix/stable/#sec-common-env">Nix
+     manual</link> for further details), while <varname>config</varname>
+     contains the full system configuration. This line can be omitted if there
+     is no reference to <varname>pkgs</varname> and <varname>config</varname>
+     inside the module.
+    </para>
+   </callout>
+   <callout arearefs='module-syntax-2'>
+    <para>
+     This list enumerates the paths to other NixOS modules that should be
+     included in the evaluation of the system configuration. A default set of
+     modules is defined in the file
+     <filename>modules/module-list.nix</filename>. These don't need to be added
+     in the import list.
+    </para>
+   </callout>
+   <callout arearefs='module-syntax-3'>
+    <para>
+     The attribute <varname>options</varname> is a nested set of
+     <emphasis>option declarations</emphasis> (described below).
+    </para>
+   </callout>
+   <callout arearefs='module-syntax-4'>
+    <para>
+     The attribute <varname>config</varname> is a nested set of
+     <emphasis>option definitions</emphasis> (also described below).
+    </para>
+   </callout>
+  </calloutlist>
+ </para>
+ <para>
+  <xref linkend='locate-example' /> shows a module that handles the regular
+  update of the “locate” database, an index of all files in the file
+  system. This module declares two options that can be defined by other modules
+  (typically the user’s <filename>configuration.nix</filename>):
+  <option>services.locate.enable</option> (whether the database should be
+  updated) and <option>services.locate.interval</option> (when the update
+  should be done). It implements its functionality by defining two options
+  declared by other modules: <option>systemd.services</option> (the set of all
+  systemd services) and <option>systemd.timers</option> (the list of commands
+  to be executed periodically by <command>systemd</command>).
+ </para>
+ <example xml:id='locate-example'>
+  <title>NixOS Module for the “locate” Service</title>
+<programlisting>
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.services.locate;
+in {
+  options.services.locate = {
+    enable = mkOption {
+      type = types.bool;
+      default = false;
+      description = ''
+        If enabled, NixOS will periodically update the database of
+        files used by the <command>locate</command> command.
+      '';
+    };
+
+    interval = mkOption {
+      type = types.str;
+      default = "02:15";
+      example = "hourly";
+      description = ''
+        Update the locate database at this interval. Updates by
+        default at 2:15 AM every day.
+
+        The format is described in
+        <citerefentry><refentrytitle>systemd.time</refentrytitle>
+        <manvolnum>7</manvolnum></citerefentry>.
+      '';
+    };
+
+    # Other options omitted for documentation
+  };
+
+  config = {
+    systemd.services.update-locatedb =
+      { description = "Update Locate Database";
+        path  = [ pkgs.su ];
+        script =
+          ''
+            mkdir -m 0755 -p $(dirname ${toString cfg.output})
+            exec updatedb \
+              --localuser=${cfg.localuser} \
+              ${optionalString (!cfg.includeStore) "--prunepaths='/nix/store'"} \
+              --output=${toString cfg.output} ${concatStringsSep " " cfg.extraFlags}
+          '';
+      };
+
+    systemd.timers.update-locatedb = mkIf cfg.enable
+      { description = "Update timer for locate database";
+        partOf      = [ "update-locatedb.service" ];
+        wantedBy    = [ "timers.target" ];
+        timerConfig.OnCalendar = cfg.interval;
+      };
+  };
+}
+</programlisting>
+ </example>
+ <xi:include href="option-declarations.xml" />
+ <xi:include href="option-types.xml" />
+ <xi:include href="option-def.xml" />
+ <xi:include href="assertions.xml" />
+ <xi:include href="meta-attributes.xml" />
+ <xi:include href="importing-modules.xml" />
+ <xi:include href="replace-modules.xml" />
+ <xi:include href="freeform-modules.xml" />
+ <xi:include href="settings-options.xml" />
+</chapter>
diff --git a/nixpkgs/nixos/doc/manual/development/writing-nixos-tests.xml b/nixpkgs/nixos/doc/manual/development/writing-nixos-tests.xml
new file mode 100644
index 000000000000..5f70f74d5d90
--- /dev/null
+++ b/nixpkgs/nixos/doc/manual/development/writing-nixos-tests.xml
@@ -0,0 +1,464 @@
+<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-writing-nixos-tests">
+ <title>Writing Tests</title>
+
+ <para>
+  A NixOS test is a Nix expression that has the following structure:
+<programlisting>
+import ./make-test-python.nix {
+
+  # Either the configuration of a single machine:
+  machine =
+    { config, pkgs, ... }:
+    { <replaceable>configuration…</replaceable>
+    };
+
+  # Or a set of machines:
+  nodes =
+    { <replaceable>machine1</replaceable> =
+        { config, pkgs, ... }: { <replaceable>…</replaceable> };
+      <replaceable>machine2</replaceable> =
+        { config, pkgs, ... }: { <replaceable>…</replaceable> };
+      …
+    };
+
+  testScript =
+    ''
+      <replaceable>Python code…</replaceable>
+    '';
+}
+</programlisting>
+  The attribute <literal>testScript</literal> is a bit of Python code that
+  executes the test (described below). During the test, it will start one or
+  more virtual machines, the configuration of which is described by the
+  attribute <literal>machine</literal> (if you need only one machine in your
+  test) or by the attribute <literal>nodes</literal> (if you need multiple
+  machines). For instance,
+  <filename
+xlink:href="https://github.com/NixOS/nixpkgs/blob/master/nixos/tests/login.nix">login.nix</filename>
+  only needs a single machine to test whether users can log in on the virtual
+  console, whether device ownership is correctly maintained when switching
+  between consoles, and so on. On the other hand,
+  <filename
+xlink:href="https://github.com/NixOS/nixpkgs/blob/master/nixos/tests/nfs/simple.nix">nfs/simple.nix</filename>,
+  which tests NFS client and server functionality in the Linux kernel
+  (including whether locks are maintained across server crashes), requires
+  three machines: a server and two clients.
+ </para>
+
+ <para>
+  There are a few special NixOS configuration options for test VMs:
+<!-- FIXME: would be nice to generate this automatically. -->
+  <variablelist>
+   <varlistentry>
+    <term>
+     <option>virtualisation.memorySize</option>
+    </term>
+    <listitem>
+     <para>
+      The memory of the VM in megabytes.
+     </para>
+    </listitem>
+   </varlistentry>
+   <varlistentry>
+    <term>
+     <option>virtualisation.vlans</option>
+    </term>
+    <listitem>
+     <para>
+      The virtual networks to which the VM is connected. See
+      <filename
+    xlink:href="https://github.com/NixOS/nixpkgs/blob/master/nixos/tests/nat.nix">nat.nix</filename>
+      for an example.
+     </para>
+    </listitem>
+   </varlistentry>
+   <varlistentry>
+    <term>
+     <option>virtualisation.writableStore</option>
+    </term>
+    <listitem>
+     <para>
+      By default, the Nix store in the VM is not writable. If you enable this
+      option, a writable union file system is mounted on top of the Nix store
+      to make it appear writable. This is necessary for tests that run Nix
+      operations that modify the store.
+     </para>
+    </listitem>
+   </varlistentry>
+  </variablelist>
+  For more options, see the module
+  <filename
+xlink:href="https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/virtualisation/qemu-vm.nix">qemu-vm.nix</filename>.
+ </para>
+
+ <para>
+  The test script is a sequence of Python statements that perform various
+  actions, such as starting VMs, executing commands in the VMs, and so on. Each
+  virtual machine is represented as an object stored in the variable
+  <literal><replaceable>name</replaceable></literal> if this is also the
+  identifier of the machine in the declarative config.
+  If you didn't specify multiple machines using the <literal>nodes</literal>
+  attribute, it is just <literal>machine</literal>.
+  The following example starts the machine, waits until it has finished booting,
+  then executes a command and checks that the output is more-or-less correct:
+<programlisting>
+machine.start()
+machine.wait_for_unit("default.target")
+if not "Linux" in machine.succeed("uname"):
+  raise Exception("Wrong OS")
+</programlisting>
+  The first line is actually unnecessary; machines are implicitly started when
+  you first execute an action on them (such as <literal>wait_for_unit</literal>
+  or <literal>succeed</literal>). If you have multiple machines, you can speed
+  up the test by starting them in parallel:
+<programlisting>
+start_all()
+</programlisting>
+ </para>
+
+ <para>
+  The following methods are available on machine objects:
+  <variablelist>
+   <varlistentry>
+    <term>
+     <methodname>start</methodname>
+    </term>
+    <listitem>
+     <para>
+      Start the virtual machine. This method is asynchronous — it does not
+      wait for the machine to finish booting.
+     </para>
+    </listitem>
+   </varlistentry>
+   <varlistentry>
+    <term>
+     <methodname>shutdown</methodname>
+    </term>
+    <listitem>
+     <para>
+      Shut down the machine, waiting for the VM to exit.
+     </para>
+    </listitem>
+   </varlistentry>
+   <varlistentry>
+    <term>
+     <methodname>crash</methodname>
+    </term>
+    <listitem>
+     <para>
+      Simulate a sudden power failure, by telling the VM to exit immediately.
+     </para>
+    </listitem>
+   </varlistentry>
+   <varlistentry>
+    <term>
+     <methodname>block</methodname>
+    </term>
+    <listitem>
+     <para>
+      Simulate unplugging the Ethernet cable that connects the machine to the
+      other machines.
+     </para>
+    </listitem>
+   </varlistentry>
+   <varlistentry>
+    <term>
+     <methodname>unblock</methodname>
+    </term>
+    <listitem>
+     <para>
+      Undo the effect of <methodname>block</methodname>.
+     </para>
+    </listitem>
+   </varlistentry>
+   <varlistentry>
+    <term>
+     <methodname>screenshot</methodname>
+    </term>
+    <listitem>
+     <para>
+      Take a picture of the display of the virtual machine, in PNG format. The
+      screenshot is linked from the HTML log.
+     </para>
+    </listitem>
+   </varlistentry>
+   <varlistentry>
+    <term>
+     <methodname>get_screen_text</methodname>
+    </term>
+    <listitem>
+     <para>
+      Return a textual representation of what is currently visible on the
+      machine's screen using optical character recognition.
+     </para>
+     <note>
+      <para>
+       This requires passing <option>enableOCR</option> to the test attribute
+       set.
+      </para>
+     </note>
+    </listitem>
+   </varlistentry>
+   <varlistentry>
+    <term>
+     <methodname>send_monitor_command</methodname>
+    </term>
+    <listitem>
+     <para>
+      Send a command to the QEMU monitor. This is rarely used, but allows doing
+      stuff such as attaching virtual USB disks to a running machine.
+     </para>
+    </listitem>
+   </varlistentry>
+   <varlistentry>
+    <term>
+     <methodname>send_key</methodname>
+    </term>
+    <listitem>
+     <para>
+      Simulate pressing keys on the virtual keyboard, e.g.,
+      <literal>send_key("ctrl-alt-delete")</literal>.
+     </para>
+    </listitem>
+   </varlistentry>
+   <varlistentry>
+    <term>
+     <methodname>send_chars</methodname>
+    </term>
+    <listitem>
+     <para>
+      Simulate typing a sequence of characters on the virtual keyboard, e.g.,
+      <literal>send_chars("foobar\n")</literal> will type the string
+      <literal>foobar</literal> followed by the Enter key.
+     </para>
+    </listitem>
+   </varlistentry>
+   <varlistentry>
+    <term>
+     <methodname>execute</methodname>
+    </term>
+    <listitem>
+     <para>
+      Execute a shell command, returning a list
+      <literal>(<replaceable>status</replaceable>,
+      <replaceable>stdout</replaceable>)</literal>.
+     </para>
+    </listitem>
+   </varlistentry>
+   <varlistentry>
+    <term>
+     <methodname>succeed</methodname>
+    </term>
+    <listitem>
+     <para>
+      Execute a shell command, raising an exception if the exit status is not
+      zero, otherwise returning the standard output.
+     </para>
+    </listitem>
+   </varlistentry>
+   <varlistentry>
+    <term>
+     <methodname>fail</methodname>
+    </term>
+    <listitem>
+     <para>
+      Like <methodname>succeed</methodname>, but raising an exception if the
+      command returns a zero status.
+     </para>
+    </listitem>
+   </varlistentry>
+   <varlistentry>
+    <term>
+     <methodname>wait_until_succeeds</methodname>
+    </term>
+    <listitem>
+     <para>
+      Repeat a shell command with 1-second intervals until it succeeds.
+     </para>
+    </listitem>
+   </varlistentry>
+   <varlistentry>
+    <term>
+     <methodname>wait_until_fails</methodname>
+    </term>
+    <listitem>
+     <para>
+      Repeat a shell command with 1-second intervals until it fails.
+     </para>
+    </listitem>
+   </varlistentry>
+   <varlistentry>
+    <term>
+     <methodname>wait_for_unit</methodname>
+    </term>
+    <listitem>
+     <para>
+      Wait until the specified systemd unit has reached the “active” state.
+     </para>
+    </listitem>
+   </varlistentry>
+   <varlistentry>
+    <term>
+     <methodname>wait_for_file</methodname>
+    </term>
+    <listitem>
+     <para>
+      Wait until the specified file exists.
+     </para>
+    </listitem>
+   </varlistentry>
+   <varlistentry>
+    <term>
+     <methodname>wait_for_open_port</methodname>
+    </term>
+    <listitem>
+     <para>
+      Wait until a process is listening on the given TCP port (on
+      <literal>localhost</literal>, at least).
+     </para>
+    </listitem>
+   </varlistentry>
+   <varlistentry>
+    <term>
+     <methodname>wait_for_closed_port</methodname>
+    </term>
+    <listitem>
+     <para>
+      Wait until nobody is listening on the given TCP port.
+     </para>
+    </listitem>
+   </varlistentry>
+   <varlistentry>
+    <term>
+     <methodname>wait_for_x</methodname>
+    </term>
+    <listitem>
+     <para>
+      Wait until the X11 server is accepting connections.
+     </para>
+    </listitem>
+   </varlistentry>
+   <varlistentry>
+    <term>
+     <methodname>wait_for_text</methodname>
+    </term>
+    <listitem>
+     <para>
+      Wait until the supplied regular expressions matches the textual contents
+      of the screen by using optical character recognition (see
+      <methodname>get_screen_text</methodname>).
+     </para>
+     <note>
+      <para>
+       This requires passing <option>enableOCR</option> to the test attribute
+       set.
+      </para>
+     </note>
+    </listitem>
+   </varlistentry>
+   <varlistentry>
+    <term>
+     <methodname>wait_for_console_text</methodname>
+    </term>
+    <listitem>
+     <para>
+      Wait until the supplied regular expressions match a line of the serial
+      console output. This method is useful when OCR is not possibile or
+      accurate enough.
+     </para>
+    </listitem>
+   </varlistentry>
+   <varlistentry>
+    <term>
+     <methodname>wait_for_window</methodname>
+    </term>
+    <listitem>
+     <para>
+      Wait until an X11 window has appeared whose name matches the given
+      regular expression, e.g., <literal>wait_for_window("Terminal")</literal>.
+     </para>
+    </listitem>
+   </varlistentry>
+   <varlistentry>
+    <term>
+     <methodname>copy_from_host</methodname>
+    </term>
+    <listitem>
+     <para>
+      Copies a file from host to machine, e.g.,
+      <literal>copy_from_host("myfile", "/etc/my/important/file")</literal>.
+     </para>
+     <para>
+      The first argument is the file on the host. The file needs to be
+      accessible while building the nix derivation. The second argument is the
+      location of the file on the machine.
+     </para>
+    </listitem>
+   </varlistentry>
+   <varlistentry>
+    <term>
+     <methodname>systemctl</methodname>
+    </term>
+    <listitem>
+     <para>
+      Runs <literal>systemctl</literal> commands with optional support for
+      <literal>systemctl --user</literal>
+     </para>
+     <para>
+<programlisting>
+machine.systemctl("list-jobs --no-pager") # runs `systemctl list-jobs --no-pager`
+machine.systemctl("list-jobs --no-pager", "any-user") # spawns a shell for `any-user` and runs `systemctl --user list-jobs --no-pager`
+</programlisting>
+     </para>
+    </listitem>
+   </varlistentry>
+  </variablelist>
+ </para>
+
+ <para>
+  To test user units declared by <literal>systemd.user.services</literal> the
+  optional <literal>user</literal> argument can be used:
+<programlisting>
+machine.start()
+machine.wait_for_x()
+machine.wait_for_unit("xautolock.service", "x-session-user")
+</programlisting>
+  This applies to <literal>systemctl</literal>, <literal>get_unit_info</literal>,
+  <literal>wait_for_unit</literal>, <literal>start_job</literal> and
+  <literal>stop_job</literal>.
+ </para>
+
+ <para>
+  For faster dev cycles it's also possible to disable the code-linters (this shouldn't
+  be commited though):
+<programlisting>
+import ./make-test-python.nix {
+  skipLint = true;
+  machine =
+    { config, pkgs, ... }:
+    { <replaceable>configuration…</replaceable>
+    };
+
+  testScript =
+    ''
+      <replaceable>Python code…</replaceable>
+    '';
+}
+</programlisting>
+  This will produce a Nix warning at evaluation time. To fully disable the
+  linter, wrap the test script in comment directives to disable the Black linter
+  directly (again, don't commit this within the Nixpkgs repository):
+<programlisting>
+  testScript =
+    ''
+      # fmt: off
+      <replaceable>Python code…</replaceable>
+      # fmt: on
+    '';
+</programlisting>
+ </para>
+</section>