<section xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" 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>
          <literal>types.bool</literal>
        </term>
        <listitem>
          <para>
            A boolean, its values can be <literal>true</literal> or
            <literal>false</literal>.
          </para>
        </listitem>
      </varlistentry>
      <varlistentry>
        <term>
          <literal>types.path</literal>
        </term>
        <listitem>
          <para>
            A filesystem path is anything that starts with a slash when
            coerced to a string. Even if derivations can be considered
            as paths, the more specific <literal>types.package</literal>
            should be preferred.
          </para>
        </listitem>
      </varlistentry>
      <varlistentry>
        <term>
          <literal>types.package</literal>
        </term>
        <listitem>
          <para>
            A top-level store path. This can be an attribute set
            pointing to a store path, like a derivation or a flake
            input.
          </para>
        </listitem>
      </varlistentry>
      <varlistentry>
        <term>
          <literal>types.enum</literal>
          <emphasis><literal>l</literal></emphasis>
        </term>
        <listitem>
          <para>
            One element of the list
            <emphasis><literal>l</literal></emphasis>, e.g.
            <literal>types.enum [ &quot;left&quot; &quot;right&quot; ]</literal>.
            Multiple definitions cannot be merged.
          </para>
        </listitem>
      </varlistentry>
      <varlistentry>
        <term>
          <literal>types.anything</literal>
        </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.
          </para>
          <anchor xml:id="ex-types-anything" />
          <para>
            <emphasis role="strong">Example:
            <literal>types.anything</literal> Example</emphasis>
          </para>
          <para>
            Two definitions of this type like
          </para>
          <programlisting language="bash">
{
  str = lib.mkDefault &quot;foo&quot;;
  pkg.hello = pkgs.hello;
  fun.fun = x: x + 1;
}
</programlisting>
          <programlisting language="bash">
{
  str = lib.mkIf true &quot;bar&quot;;
  pkg.gcc = pkgs.gcc;
  fun.fun = lib.mkForce (x: x + 2);
}
</programlisting>
          <para>
            will get merged to
          </para>
          <programlisting language="bash">
{
  str = &quot;bar&quot;;
  pkg.gcc = pkgs.gcc;
  pkg.hello = pkgs.hello;
  fun.fun = x: x + 2;
}
</programlisting>
        </listitem>
      </varlistentry>
      <varlistentry>
        <term>
          <literal>types.raw</literal>
        </term>
        <listitem>
          <para>
            A type which doesn’t do any checking, merging or nested
            evaluation. It accepts a single arbitrary value that is not
            recursed into, making it useful for values coming from
            outside the module system, such as package sets or arbitrary
            data. Options of this type are still evaluated according to
            priorities and conditionals, so <literal>mkForce</literal>,
            <literal>mkIf</literal> and co. still work on the option
            value itself, but not for any value nested within it. This
            type should only be used when checking, merging and nested
            evaluation are not desirable.
          </para>
        </listitem>
      </varlistentry>
      <varlistentry>
        <term>
          <literal>types.optionType</literal>
        </term>
        <listitem>
          <para>
            The type of an option’s type. Its merging operation ensures
            that nested options have the correct file location
            annotated, and that if possible, multiple option definitions
            are correctly merged together. The main use case is as the
            type of the <literal>_module.freeformType</literal> option.
          </para>
        </listitem>
      </varlistentry>
      <varlistentry>
        <term>
          <literal>types.attrs</literal>
        </term>
        <listitem>
          <para>
            A free-form attribute set.
          </para>
          <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>
        </listitem>
      </varlistentry>
    </variablelist>
    <section xml:id="sec-option-types-numeric">
      <title>Numeric types</title>
      <variablelist>
        <varlistentry>
          <term>
            <literal>types.int</literal>
          </term>
          <listitem>
            <para>
              A signed integer.
            </para>
          </listitem>
        </varlistentry>
        <varlistentry>
          <term>
            <literal>types.ints.{s8, s16, s32}</literal>
          </term>
          <listitem>
            <para>
              Signed integers with a fixed length (8, 16 or 32 bits).
              They go from −2^n/2 to 2^n/2−1 respectively (e.g.
              <literal>−128</literal> to <literal>127</literal> for 8
              bits).
            </para>
          </listitem>
        </varlistentry>
        <varlistentry>
          <term>
            <literal>types.ints.unsigned</literal>
          </term>
          <listitem>
            <para>
              An unsigned integer (that is &gt;= 0).
            </para>
          </listitem>
        </varlistentry>
        <varlistentry>
          <term>
            <literal>types.ints.{u8, u16, u32}</literal>
          </term>
          <listitem>
            <para>
              Unsigned integers with a fixed length (8, 16 or 32 bits).
              They go from 0 to 2^n−1 respectively (e.g.
              <literal>0</literal> to <literal>255</literal> for 8
              bits).
            </para>
          </listitem>
        </varlistentry>
        <varlistentry>
          <term>
            <literal>types.ints.between</literal>
            <emphasis><literal>lowest highest</literal></emphasis>
          </term>
          <listitem>
            <para>
              An integer between
              <emphasis><literal>lowest</literal></emphasis> and
              <emphasis><literal>highest</literal></emphasis> (both
              inclusive).
            </para>
          </listitem>
        </varlistentry>
        <varlistentry>
          <term>
            <literal>types.ints.positive</literal>
          </term>
          <listitem>
            <para>
              A positive integer (that is &gt; 0).
            </para>
          </listitem>
        </varlistentry>
        <varlistentry>
          <term>
            <literal>types.port</literal>
          </term>
          <listitem>
            <para>
              A port number. This type is an alias to
              <literal>types.ints.u16</literal>.
            </para>
          </listitem>
        </varlistentry>
        <varlistentry>
          <term>
            <literal>types.float</literal>
          </term>
          <listitem>
            <para>
              A floating point number.
            </para>
            <warning>
              <para>
                Converting a floating point number to a string with
                <literal>toString</literal> or <literal>toJSON</literal>
                may result in
                <link xlink:href="https://github.com/NixOS/nix/issues/5733">precision
                loss</link>.
              </para>
            </warning>
          </listitem>
        </varlistentry>
        <varlistentry>
          <term>
            <literal>types.number</literal>
          </term>
          <listitem>
            <para>
              Either a signed integer or a floating point number. No
              implicit conversion is done between the two types, and
              multiple equal definitions will only be merged if they
              have the same type.
            </para>
          </listitem>
        </varlistentry>
        <varlistentry>
          <term>
            <literal>types.numbers.between</literal>
            <emphasis><literal>lowest highest</literal></emphasis>
          </term>
          <listitem>
            <para>
              An integer or floating point number between
              <emphasis><literal>lowest</literal></emphasis> and
              <emphasis><literal>highest</literal></emphasis> (both
              inclusive).
            </para>
          </listitem>
        </varlistentry>
        <varlistentry>
          <term>
            <literal>types.numbers.nonnegative</literal>
          </term>
          <listitem>
            <para>
              A nonnegative integer or floating point number (that is
              &gt;= 0).
            </para>
          </listitem>
        </varlistentry>
        <varlistentry>
          <term>
            <literal>types.numbers.positive</literal>
          </term>
          <listitem>
            <para>
              A positive integer or floating point number (that is &gt;
              0).
            </para>
          </listitem>
        </varlistentry>
      </variablelist>
    </section>
    <section xml:id="sec-option-types-string">
      <title>String types</title>
      <variablelist>
        <varlistentry>
          <term>
            <literal>types.str</literal>
          </term>
          <listitem>
            <para>
              A string. Multiple definitions cannot be merged.
            </para>
          </listitem>
        </varlistentry>
        <varlistentry>
          <term>
            <literal>types.separatedString</literal>
            <emphasis><literal>sep</literal></emphasis>
          </term>
          <listitem>
            <para>
              A string. Multiple definitions are concatenated with
              <emphasis><literal>sep</literal></emphasis>, e.g.
              <literal>types.separatedString &quot;|&quot;</literal>.
            </para>
          </listitem>
        </varlistentry>
        <varlistentry>
          <term>
            <literal>types.lines</literal>
          </term>
          <listitem>
            <para>
              A string. Multiple definitions are concatenated with a new
              line <literal>&quot;\n&quot;</literal>.
            </para>
          </listitem>
        </varlistentry>
        <varlistentry>
          <term>
            <literal>types.commas</literal>
          </term>
          <listitem>
            <para>
              A string. Multiple definitions are concatenated with a
              comma <literal>&quot;,&quot;</literal>.
            </para>
          </listitem>
        </varlistentry>
        <varlistentry>
          <term>
            <literal>types.envVar</literal>
          </term>
          <listitem>
            <para>
              A string. Multiple definitions are concatenated with a
              colon <literal>&quot;:&quot;</literal>.
            </para>
          </listitem>
        </varlistentry>
        <varlistentry>
          <term>
            <literal>types.strMatching</literal>
          </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>
  <section xml:id="sec-option-types-submodule">
    <title>Submodule types</title>
    <para>
      Submodules are detailed in
      <link linkend="section-option-types-submodule">Submodule</link>.
    </para>
    <variablelist>
      <varlistentry>
        <term>
          <literal>types.submodule</literal>
          <emphasis><literal>o</literal></emphasis>
        </term>
        <listitem>
          <para>
            A set of sub options
            <emphasis><literal>o</literal></emphasis>.
            <emphasis><literal>o</literal></emphasis> 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>.
          </para>
        </listitem>
      </varlistentry>
      <varlistentry>
        <term>
          <literal>types.submoduleWith</literal> {
          <emphasis><literal>modules</literal></emphasis>,
          <emphasis><literal>specialArgs</literal></emphasis> ? {},
          <emphasis><literal>shorthandOnlyDefinesConfig</literal></emphasis>
          ? false }
        </term>
        <listitem>
          <para>
            Like <literal>types.submodule</literal>, but more flexible
            and with better defaults. It has parameters
          </para>
          <itemizedlist>
            <listitem>
              <para>
                <emphasis><literal>modules</literal></emphasis> 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.
              </para>
              <note>
                <para>
                  Only options defined with this argument are included
                  in rendered documentation.
                </para>
              </note>
            </listitem>
            <listitem>
              <para>
                <emphasis><literal>specialArgs</literal></emphasis> 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.
                <emphasis><literal>specialArgs</literal></emphasis>
                should only be used for arguments that can't go through
                the module fixed-point, because of infinite recursion or
                other problems. An example is overriding the
                <literal>lib</literal> argument, because
                <literal>lib</literal> itself is used to define
                <literal>_module.args</literal>, which makes using
                <literal>_module.args</literal> to define it impossible.
              </para>
            </listitem>
            <listitem>
              <para>
                <emphasis><literal>shorthandOnlyDefinesConfig</literal></emphasis>
                Whether definitions of this type should default to the
                <literal>config</literal> section of a module (see
                <link linkend="ex-module-syntax">Example: Structure of
                NixOS Modules</link>) 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 = &quot;value&quot;</literal>
                instead of requiring
                <literal>the-submodule.config.config = &quot;value&quot;</literal>.
                This is because only when modules
                <emphasis>don'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>
        </listitem>
      </varlistentry>
      <varlistentry>
        <term>
          <literal>types.deferredModule</literal>
        </term>
        <listitem>
          <para>
            Whereas <literal>submodule</literal> represents an option
            tree, <literal>deferredModule</literal> represents a module
            value, such as a module file or a configuration.
          </para>
          <para>
            It can be set multiple times.
          </para>
          <para>
            Module authors can use its value in
            <literal>imports</literal>, in
            <literal>submoduleWith</literal><quote>s
            <literal>modules</literal> or in
            <literal>evalModules</literal></quote>
            <literal>modules</literal> parameter, among other places.
          </para>
          <para>
            Note that <literal>imports</literal> must be evaluated
            before the module fixpoint. Because of this, deferred
            modules can only be imported into <quote>other</quote>
            fixpoints, such as submodules.
          </para>
          <para>
            One use case for this type is the type of a
            <quote>default</quote> module that allow the user to affect
            all submodules in an <literal>attrsOf submodule</literal> at
            once. This is more convenient and discoverable than
            expecting the module user to type-merge with the
            <literal>attrsOf submodule</literal> option.
          </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>
          <literal>types.listOf</literal>
          <emphasis><literal>t</literal></emphasis>
        </term>
        <listitem>
          <para>
            A list of <emphasis><literal>t</literal></emphasis> type,
            e.g. <literal>types.listOf int</literal>. Multiple
            definitions are merged with list concatenation.
          </para>
        </listitem>
      </varlistentry>
      <varlistentry>
        <term>
          <literal>types.attrsOf</literal>
          <emphasis><literal>t</literal></emphasis>
        </term>
        <listitem>
          <para>
            An attribute set of where all the values are of
            <emphasis><literal>t</literal></emphasis> type. Multiple
            definitions result in the joined attribute set.
          </para>
          <note>
            <para>
              This type is <emphasis>strict</emphasis> in its values,
              which in turn means attributes cannot depend on other
              attributes. See <literal> types.lazyAttrsOf</literal> for
              a lazy version.
            </para>
          </note>
        </listitem>
      </varlistentry>
      <varlistentry>
        <term>
          <literal>types.lazyAttrsOf</literal>
          <emphasis><literal>t</literal></emphasis>
        </term>
        <listitem>
          <para>
            An attribute set of where all the values are of
            <emphasis><literal>t</literal></emphasis> type. Multiple
            definitions result in the joined attribute set. This is the
            lazy version of <literal>types.attrsOf </literal>, allowing
            attributes to depend on each other.
          </para>
          <warning>
            <para>
              This version does not fully support conditional
              definitions! With an option <literal>foo</literal> 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
              <emphasis><literal>t</literal></emphasis> 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>
        </listitem>
      </varlistentry>
      <varlistentry>
        <term>
          <literal>types.nullOr</literal>
          <emphasis><literal>t</literal></emphasis>
        </term>
        <listitem>
          <para>
            <literal>null</literal> or type
            <emphasis><literal>t</literal></emphasis>. Multiple
            definitions are merged according to type
            <emphasis><literal>t</literal></emphasis>.
          </para>
        </listitem>
      </varlistentry>
      <varlistentry>
        <term>
          <literal>types.uniq</literal>
          <emphasis><literal>t</literal></emphasis>
        </term>
        <listitem>
          <para>
            Ensures that type <emphasis><literal>t</literal></emphasis>
            cannot be merged. It is used to ensure option definitions
            are declared only once.
          </para>
        </listitem>
      </varlistentry>
      <varlistentry>
        <term>
          <literal>types.unique</literal>
          <literal>{ message = m }</literal>
          <emphasis><literal>t</literal></emphasis>
        </term>
        <listitem>
          <para>
            Ensures that type <emphasis><literal>t</literal></emphasis>
            cannot be merged. Prints the message
            <emphasis><literal>m</literal></emphasis>, after the line
            <literal>The option &lt;option path&gt; is defined multiple times.</literal>
            and before a list of definition locations.
          </para>
        </listitem>
      </varlistentry>
      <varlistentry>
        <term>
          <literal>types.either</literal>
          <emphasis><literal>t1 t2</literal></emphasis>
        </term>
        <listitem>
          <para>
            Type <emphasis><literal>t1</literal></emphasis> or type
            <emphasis><literal>t2</literal></emphasis>, e.g.
            <literal>with types; either int str</literal>. Multiple
            definitions cannot be merged.
          </para>
        </listitem>
      </varlistentry>
      <varlistentry>
        <term>
          <literal>types.oneOf</literal> [
          <emphasis><literal>t1 t2</literal></emphasis> ... ]
        </term>
        <listitem>
          <para>
            Type <emphasis><literal>t1</literal></emphasis> or type
            <emphasis><literal>t2</literal></emphasis> and so forth,
            e.g. <literal>with types; oneOf [ int str bool ]</literal>.
            Multiple definitions cannot be merged.
          </para>
        </listitem>
      </varlistentry>
      <varlistentry>
        <term>
          <literal>types.coercedTo</literal>
          <emphasis><literal>from f to</literal></emphasis>
        </term>
        <listitem>
          <para>
            Type <emphasis><literal>to</literal></emphasis> or type
            <emphasis><literal>from</literal></emphasis> which will be
            coerced to type <emphasis><literal>to</literal></emphasis>
            using function <emphasis><literal>f</literal></emphasis>
            which takes an argument of type
            <emphasis><literal>from</literal></emphasis> and return a
            value of type <emphasis><literal>to</literal></emphasis>.
            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 <emphasis><literal>o</literal></emphasis>,
      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
      (<link linkend="ex-submodule-direct">Example: Directly defined
      submodule</link>) or as reference
      (<link linkend="ex-submodule-reference">Example: Submodule defined
      as a reference</link>).
    </para>
    <para>
      Note that even if your submodule’s options all have a default
      value, you will still need to provide a default value (e.g. an
      empty attribute set) if you want to allow users to leave it
      undefined.
    </para>
    <anchor xml:id="ex-submodule-direct" />
    <para>
      <emphasis role="strong">Example: Directly defined
      submodule</emphasis>
    </para>
    <programlisting language="bash">
options.mod = mkOption {
  description = &quot;submodule example&quot;;
  type = with types; submodule {
    options = {
      foo = mkOption {
        type = int;
      };
      bar = mkOption {
        type = str;
      };
    };
  };
};
</programlisting>
    <anchor xml:id="ex-submodule-reference" />
    <para>
      <emphasis role="strong">Example: Submodule defined as a
      reference</emphasis>
    </para>
    <programlisting language="bash">
let
  modOptions = {
    options = {
      foo = mkOption {
        type = int;
      };
      bar = mkOption {
        type = int;
      };
    };
  };
in
options.mod = mkOption {
  description = &quot;submodule example&quot;;
  type = with types; submodule modOptions;
};
</programlisting>
    <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>
      (<link linkend="ex-submodule-listof-declaration">Example:
      Declaration of a list of submodules</link>),
      <literal>submodule</literal> allows multiple definitions of the
      submodule option set
      (<link linkend="ex-submodule-listof-definition">Example:
      Definition of a list of submodules</link>).
    </para>
    <anchor xml:id="ex-submodule-listof-declaration" />
    <para>
      <emphasis role="strong">Example: Declaration of a list of
      submodules</emphasis>
    </para>
    <programlisting language="bash">
options.mod = mkOption {
  description = &quot;submodule example&quot;;
  type = with types; listOf (submodule {
    options = {
      foo = mkOption {
        type = int;
      };
      bar = mkOption {
        type = str;
      };
    };
  });
};
</programlisting>
    <anchor xml:id="ex-submodule-listof-definition" />
    <para>
      <emphasis role="strong">Example: Definition of a list of
      submodules</emphasis>
    </para>
    <programlisting language="bash">
config.mod = [
  { foo = 1; bar = &quot;one&quot;; }
  { foo = 2; bar = &quot;two&quot;; }
];
</programlisting>
    <para>
      When composed with <literal>attrsOf</literal>
      (<link linkend="ex-submodule-attrsof-declaration">Example:
      Declaration of attribute sets of submodules</link>),
      <literal>submodule</literal> allows multiple named definitions of
      the submodule option set
      (<link linkend="ex-submodule-attrsof-definition">Example:
      Definition of attribute sets of submodules</link>).
    </para>
    <anchor xml:id="ex-submodule-attrsof-declaration" />
    <para>
      <emphasis role="strong">Example: Declaration of attribute sets of
      submodules</emphasis>
    </para>
    <programlisting language="bash">
options.mod = mkOption {
  description = &quot;submodule example&quot;;
  type = with types; attrsOf (submodule {
    options = {
      foo = mkOption {
        type = int;
      };
      bar = mkOption {
        type = str;
      };
    };
  });
};
</programlisting>
    <anchor xml:id="ex-submodule-attrsof-definition" />
    <para>
      <emphasis role="strong">Example: Definition of attribute sets of
      submodules</emphasis>
    </para>
    <programlisting language="bash">
config.mod.one = { foo = 1; bar = &quot;one&quot;; };
config.mod.two = { foo = 2; bar = &quot;two&quot;; };
</programlisting>
  </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>
          <literal>check</literal>
        </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
            (<link linkend="ex-extending-type-check-1">Example: Adding a
            type check</link>), or to fully override the check function
            (<link linkend="ex-extending-type-check-2">Example:
            Overriding a type check</link>).
          </para>
          <anchor xml:id="ex-extending-type-check-1" />
          <para>
            <emphasis role="strong">Example: Adding a type
            check</emphasis>
          </para>
          <programlisting language="bash">
byte = mkOption {
  description = &quot;An integer between 0 and 255.&quot;;
  type = types.addCheck types.int (x: x &gt;= 0 &amp;&amp; x &lt;= 255);
};
</programlisting>
          <anchor xml:id="ex-extending-type-check-2" />
          <para>
            <emphasis role="strong">Example: Overriding a type
            check</emphasis>
          </para>
          <programlisting language="bash">
nixThings = mkOption {
  description = &quot;words that start with 'nix'&quot;;
  type = types.str // {
    check = (x: lib.hasPrefix &quot;nix&quot; x)
  };
};
</programlisting>
        </listitem>
      </varlistentry>
      <varlistentry>
        <term>
          <literal>merge</literal>
        </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 <literal>types.nix</literal>
      code before creating a new type.
    </para>
    <para>
      The only required parameter is <literal>name</literal>.
    </para>
    <variablelist>
      <varlistentry>
        <term>
          <literal>name</literal>
        </term>
        <listitem>
          <para>
            A string representation of the type function name.
          </para>
        </listitem>
      </varlistentry>
      <varlistentry>
        <term>
          <literal>definition</literal>
        </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>
          <literal>check</literal>
        </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>
          <literal>merge</literal>
        </term>
        <listitem>
          <para>
            A function to merge multiple definitions values. Takes two
            parameters:
          </para>
          <variablelist>
            <varlistentry>
              <term>
                <emphasis><literal>loc</literal></emphasis>
              </term>
              <listitem>
                <para>
                  The option path as a list of strings, e.g.
                  <literal>[&quot;boot&quot; &quot;loader &quot;grub&quot; &quot;enable&quot;]</literal>.
                </para>
              </listitem>
            </varlistentry>
            <varlistentry>
              <term>
                <emphasis><literal>defs</literal></emphasis>
              </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 = &quot;/foo.nix&quot;; value = 1; } { file = &quot;/bar.nix&quot;; 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>
          <literal>getSubOptions</literal>
        </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 ++ [&quot;prefix&quot;])</literal>
            where
            <emphasis><literal>&quot;prefix&quot;</literal></emphasis>
            is the newly added prefix.
          </para>
        </listitem>
      </varlistentry>
      <varlistentry>
        <term>
          <literal>getSubModules</literal>
        </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>
          <literal>substSubModules</literal>
        </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>
          <literal>typeMerge</literal>
        </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>
                <emphasis><literal>f</literal></emphasis>
              </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>
          <literal>functor</literal>
        </term>
        <listitem>
          <para>
            An attribute set representing the type. It is used for type
            operations and has the following keys:
          </para>
          <variablelist>
            <varlistentry>
              <term>
                <literal>type</literal>
              </term>
              <listitem>
                <para>
                  The type function.
                </para>
              </listitem>
            </varlistentry>
            <varlistentry>
              <term>
                <literal>wrapped</literal>
              </term>
              <listitem>
                <para>
                  Holds the type parameter for composed types.
                </para>
              </listitem>
            </varlistentry>
            <varlistentry>
              <term>
                <literal>payload</literal>
              </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>
                <literal>binOp</literal>
              </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>
