<section xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" 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:
  </para>
  <programlisting language="bash">
options = {
  name = mkOption {
    type = type specification;
    default = default value;
    example = example value;
    description = lib.mdDoc &quot;Description for use in the NixOS manual.&quot;;
  };
};
</programlisting>
  <para>
    The attribute names within the <literal>name</literal> 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
    <literal>services.nix-serve.bindAddress</literal> references the
    <literal>nix-serve</literal> Nixpkgs package.
  </para>
  <para>
    The function <literal>mkOption</literal> accepts the following
    arguments.
  </para>
  <variablelist>
    <varlistentry>
      <term>
        <literal>type</literal>
      </term>
      <listitem>
        <para>
          The type of the option (see
          <xref linkend="sec-option-types" />). This argument is
          mandatory for nixpkgs modules. Setting this is highly
          recommended for the sake of documentation and type checking.
          In case it is not set, a fallback type with unspecified
          behavior is used.
        </para>
      </listitem>
    </varlistentry>
    <varlistentry>
      <term>
        <literal>default</literal>
      </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>
        <literal>defaultText</literal>
      </term>
      <listitem>
        <para>
          A textual representation of the default value to be rendered
          verbatim in the manual. Useful if the default value is a
          complex expression or depends on other values or packages. Use
          <literal>lib.literalExpression</literal> for a Nix expression,
          <literal>lib.literalMD</literal> for a plain English
          description in
          <link xlink:href="https://nixos.org/nixpkgs/manual/#sec-contributing-markup">Nixpkgs-flavored
          Markdown</link> format.
        </para>
      </listitem>
    </varlistentry>
    <varlistentry>
      <term>
        <literal>example</literal>
      </term>
      <listitem>
        <para>
          An example value that will be shown in the NixOS manual. You
          can use <literal>lib.literalExpression</literal> and
          <literal>lib.literalMD</literal> in the same way as in
          <literal>defaultText</literal>.
        </para>
      </listitem>
    </varlistentry>
    <varlistentry>
      <term>
        <literal>description</literal>
      </term>
      <listitem>
        <para>
          A textual description of the option, in
          <link xlink:href="https://nixos.org/nixpkgs/manual/#sec-contributing-markup">Nixpkgs-flavored
          Markdown</link> format, that will be included in the NixOS
          manual. During the migration process from DocBook it is
          necessary to mark descriptions written in CommonMark with
          <literal>lib.mdDoc</literal>. The description may still be
          written in DocBook (without any marker), but this is
          discouraged and will be deprecated in the future.
        </para>
      </listitem>
    </varlistentry>
  </variablelist>
  <section xml:id="sec-option-declarations-util">
    <title>Utility functions for common option patterns</title>
    <section xml:id="sec-option-declarations-util-mkEnableOption">
      <title><literal>mkEnableOption</literal></title>
      <para>
        Creates an Option attribute set for a boolean value option i.e
        an option to be toggled on or off.
      </para>
      <para>
        This function takes a single string argument, the name of the
        thing to be toggled.
      </para>
      <para>
        The option’s description is <quote>Whether to enable
        &lt;name&gt;.</quote>.
      </para>
      <para>
        For example:
      </para>
      <anchor xml:id="ex-options-declarations-util-mkEnableOption-magic" />
      <programlisting language="bash">
lib.mkEnableOption &quot;magic&quot;
# is like
lib.mkOption {
  type = lib.types.bool;
  default = false;
  example = true;
  description = lib.mdDoc &quot;Whether to enable magic.&quot;;
}
</programlisting>
      <section xml:id="sec-option-declarations-util-mkPackageOption">
        <title><literal>mkPackageOption</literal>,
        <literal>mkPackageOptionMD</literal></title>
        <para>
          Usage:
        </para>
        <programlisting language="bash">
mkPackageOption pkgs &quot;name&quot; { default = [ &quot;path&quot; &quot;in&quot; &quot;pkgs&quot; ]; example = &quot;literal example&quot;; }
</programlisting>
        <para>
          Creates an Option attribute set for an option that specifies
          the package a module should use for some purpose.
        </para>
        <para>
          <emphasis role="strong">Note</emphasis>: You shouldn’t
          necessarily make package options for all of your modules. You
          can always overwrite a specific package throughout nixpkgs by
          using
          <link xlink:href="https://nixos.org/manual/nixpkgs/stable/#chap-overlays">nixpkgs
          overlays</link>.
        </para>
        <para>
          The default package is specified as a list of strings
          representing its attribute path in nixpkgs. Because of this,
          you need to pass nixpkgs itself as the first argument.
        </para>
        <para>
          The second argument is the name of the option, used in the
          description <quote>The &lt;name&gt; package to use.</quote>.
          You can also pass an example value, either a literal string or
          a package’s attribute path.
        </para>
        <para>
          You can omit the default path if the name of the option is
          also attribute path in nixpkgs.
        </para>
        <para>
          During the transition to CommonMark documentation
          <literal>mkPackageOption</literal> creates an option with a
          DocBook description attribute, once the transition is
          completed it will create a CommonMark description instead.
          <literal>mkPackageOptionMD</literal> always creates an option
          with a CommonMark description attribute and will be removed
          some time after the transition is completed.
        </para>
        <anchor xml:id="ex-options-declarations-util-mkPackageOption" />
        <para>
          Examples:
        </para>
        <anchor xml:id="ex-options-declarations-util-mkPackageOption-hello" />
        <programlisting language="bash">
lib.mkPackageOption pkgs &quot;hello&quot; { }
# is like
lib.mkOption {
  type = lib.types.package;
  default = pkgs.hello;
  defaultText = lib.literalExpression &quot;pkgs.hello&quot;;
  description = lib.mdDoc &quot;The hello package to use.&quot;;
}
</programlisting>
        <anchor xml:id="ex-options-declarations-util-mkPackageOption-ghc" />
        <programlisting language="bash">
lib.mkPackageOption pkgs &quot;GHC&quot; {
  default = [ &quot;ghc&quot; ];
  example = &quot;pkgs.haskell.packages.ghc92.ghc.withPackages (hkgs: [ hkgs.primes ])&quot;;
}
# is like
lib.mkOption {
  type = lib.types.package;
  default = pkgs.ghc;
  defaultText = lib.literalExpression &quot;pkgs.ghc&quot;;
  example = lib.literalExpression &quot;pkgs.haskell.packages.ghc92.ghc.withPackages (hkgs: [ hkgs.primes ])&quot;;
  description = lib.mdDoc &quot;The GHC package to use.&quot;;
}
</programlisting>
        <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 approaches we could take with this module
            structure:
          </para>
          <itemizedlist>
            <listitem>
              <para>
                Configuring the display managers independently by adding
                an enable option to every display manager module
                backend. (NixOS)
              </para>
            </listitem>
            <listitem>
              <para>
                Configuring the display managers in the central module
                by adding an option to select which display manager
                backend to use.
              </para>
            </listitem>
          </itemizedlist>
          <para>
            Both approaches have problems.
          </para>
          <para>
            Making backends independent can quickly become hard to
            manage. For display managers, there can only be one enabled
            at a time, but the type system cannot enforce this
            restriction as there is no relation between each backend’s
            <literal>enable</literal> option. As a result, this
            restriction has to be done explicitly by adding assertions
            in each display manager backend module.
          </para>
          <para>
            On the other hand, managing the display manager backends in
            the central module will require changing 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
            (<link linkend="ex-option-declaration-eot-service">Example:
            Extensible type placeholder in the service module</link>),
            and to extend it in each backend module
            (<link linkend="ex-option-declaration-eot-backend-gdm">Example:
            Extending
            <literal>services.xserver.displayManager.enable</literal> in
            the <literal>gdm</literal> module</link>,
            <link linkend="ex-option-declaration-eot-backend-sddm">Example:
            Extending
            <literal>services.xserver.displayManager.enable</literal> in
            the <literal>sddm</literal> module</link>).
          </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 enforces that there
            can only be a single display manager enabled.
          </para>
          <anchor xml:id="ex-option-declaration-eot-service" />
          <para>
            <emphasis role="strong">Example: Extensible type placeholder
            in the service module</emphasis>
          </para>
          <programlisting language="bash">
services.xserver.displayManager.enable = mkOption {
  description = &quot;Display manager to use&quot;;
  type = with types; nullOr (enum [ ]);
};
</programlisting>
          <anchor xml:id="ex-option-declaration-eot-backend-gdm" />
          <para>
            <emphasis role="strong">Example: Extending
            <literal>services.xserver.displayManager.enable</literal> in
            the <literal>gdm</literal> module</emphasis>
          </para>
          <programlisting language="bash">
services.xserver.displayManager.enable = mkOption {
  type = with types; nullOr (enum [ &quot;gdm&quot; ]);
};
</programlisting>
          <anchor xml:id="ex-option-declaration-eot-backend-sddm" />
          <para>
            <emphasis role="strong">Example: Extending
            <literal>services.xserver.displayManager.enable</literal> in
            the <literal>sddm</literal> module</emphasis>
          </para>
          <programlisting language="bash">
services.xserver.displayManager.enable = mkOption {
  type = with types; nullOr (enum [ &quot;sddm&quot; ]);
};
</programlisting>
          <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 [ &quot;foo&quot; &quot;bar&quot; ])</literal>
            or
            <literal>with types; listOf (enum [ &quot;foo&quot; &quot;bar&quot; ])</literal>.
          </para>
        </section>
      </section>
    </section>
  </section>
</section>
