NixOS modules: Difference between revisions

From NixOS Wiki
imported>Mth
m Mth moved page NixOS Modules to Module
imported>Mth
No edit summary
Line 1: Line 1:
NixOS has modules to have non-intrusive extensions.  Modules are made to avoid manipulating the core of NixOS while allowing the user to separate their <code>configuration.nix</code> file into multiple sub-file which are specific to a device or a service configuration. Such separation permits the creation of services which can be tested for a while before being merged in the main line of NixOS.
'''Modules''' are files combined by NixOS to produce the full system configuration. A module contains a Nix expression. It ''declares'' options for other modules to ''define'' (give a value). It processes them and defines options declared in other modules.<ref>{{manual:nixos|sec=#sec-writing-modules|chapter=Chapter 42. Writing NixOS Modules}}</ref>


This page describes how you can create a module. If you want a pratical view, you should have a look into this small [[NixOS:extend_NixOS|tutorial]].
For example, {{ic|/etc/nixos/configuration.nix}} is a module. Most other modules are in {{Nixpkgs Link|nixos/modules}}.


== Vocabulary ==
== Structure ==


* [[NixOS:Declaration|Declaration]]: All options which are used with the <code>mkOption</code> function are declared.  Declared options should at least have a <code>description</code> attribute which contains a multiple-line text for describing the effect of the option.
Modules have the following syntax:
* [[NixOS:Definition|Definition]]: All options which are set to plain values are considered as definitions.  The plain value may vary depending on the expected type of the option.
* Use: All result of options which are used to compute values of other option are option usages.
* [[NixOS:Properties|Properties]]: These are option definition modifiers.  Properties may change the influence of an option definition in the computation of an option result.
 
To find all files which are defining or declaring an option, you may refer to the generated [http://nixos.org/nixos/manual NixOS manual] or to the <code>man</code> page of <code>configuration.nix</code>.
 
== Syntax ==
 
Modules are declared with the following syntax:


<syntaxhighlight lang="nix">
<syntaxhighlight lang="nix">
{
{
   imports = [
   imports = [
     # list of path to other modules.
     # paths to other modules
   ];
   ];


   options = {
   options = {
     # attribute set of option declarations.
     # option declarations
   };
   };


   config = {
   config = {
     # attribute set of option definitions.
     # option definitions
   };
   };
}
}
</syntaxhighlight>
</syntaxhighlight>


Another syntax exists for cases where no option declaration are necessary:
There is a shorthand for modules without any declarations:


<syntaxhighlight lang="nix">
<syntaxhighlight lang="nix">
{
{
   require = [
   require = [
     # list of path to other modules.
     # paths to other modules
   ];
   ];


   # attribute set of option definitions.
   # option definitions
}
}
</syntaxhighlight>
</syntaxhighlight>


Both of the previous syntax can be refined with an attribute set argument added on top:
=== Function ===
 
A module can be turned into a function accepting an attribute set.


<syntaxhighlight lang="nix">
<syntaxhighlight lang="nix">
{config, pkgs, ...}:
{ config, pkgs, ... }:
 
{
{
   # ...
   # ...
Line 54: Line 46:
</syntaxhighlight>
</syntaxhighlight>


The following arguments can be retrieved from this attribute set:
It may require the attribute set to contain:
* [[NixOS:config_argument|<code>config</code>]]: The configuration of the entire system.
* <code>options</code>: All option declarations refined with all definition and declaration references.
* <code>pkgs</code>: The attribute set extracted from the Nix package collection and enhanced with the <code>nixpkgs.config</code> option.
* <code>modulesPath</code>: The location of the <code>module</code> directory of NixOS.


For more information, you should refer to NixOS sources, with more insight into [https://github.com/NixOS/nixos/blob/master/lib/eval-config.nix <code>nixos/lib/eval-config.nix</code>].
<dl>
<dt>[[NixOS:config_argument|<code>config</code>]]</dt>
<dd>The configuration of the entire system.</dd>
<dt><code>options</code></dt>
<dd>All option declarations refined with all definition and declaration references.</dd>
<dt><code>pkgs</code></dt>
<dd>The attribute set extracted from the Nix package collection and enhanced with the <code>nixpkgs.config</code> option.</dd>
<dt><code>modulesPath</code></dt>
<dd>The location of the <code>module</code> directory of NixOS.</dd>
</dl>


More computation or organisation can be necessary to enhance modules.  In which case, you can add a <code>let .. in ..</code> statement between the argument and the attribute set.
=== Imports ===


<syntaxhighlight lang="nix">
Imports are paths to other NixOS modules that should be included in the evaluation of the system configuration. A default set of modules is defined in {{Nixpkgs Link|nixos/modules/module-list.nix}}. These don't need to be added in the import list.  
{config, pkgs, ...}:
 
=== Declarations ===


let
Declarations specify a module's external interfaces.
  # intermediate result.
in


{
<syntaxhighlight lang=nix>
optionName = mkOption {
   # ...
   # ...
}
}
</syntaxhighlight>
</syntaxhighlight>


== Example Module ==
They are created with {{ic|mkOption}}, a function accepting a set with following attributes:<ref>{{Nixpkgs Link|lib/options.nix#L21-L54}}</ref><ref>{{manual:nixos|sec=#sec-option-declarations|chapter=42.1. Option Declarations}}</ref>
 
<dl>
<dt><code>type</code></dt>
<dd><p>
      The type of the option. It may
      be omitted, but that’s not advisable since it may lead to errors that
      are hard to diagnose.
</p></dd>
<dt><code>default</code></dt>
<dd><p>
      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.
</p></dd>
<dt><code class="varname">example</code></dt>
<dd><p>
      An example value that will be shown in the NixOS manual.
</p></dd>
<dt><code>description</code></dt>
<dd><p>
      A textual description of the option, in DocBook format, that will be
      included in the NixOS manual.
</p></dd>
</dl>
 
== Rationale ==
 
Modules were introduced to allow extending NixOS without modifying its source code.<ref>[https://nixos.org/nix-dev/2008-November/001467.html <nowiki>[Nix-dev] NixOS: New scheme</nowiki>]</ref> They also allow splitting up <code>configuration.nix</code>, making the system configuration easier to maintain and to reuse.
 
== Example ==


put into <code>hello.nix</code> in the same folder as your <code>configuration.nix</code>.
put into <code>hello.nix</code> in the same folder as your <code>configuration.nix</code>.
Line 181: Line 209:
== References ==
== References ==


* [http://nixos.org/nixos/manual/ NixOS Documentation]
<references />


== Related Work ==
== See also ==


* Debian [http://wiki.debian.org/PackageConfigUpgrade Config::Model]:
* [[NixOS:extend_NixOS]]
target configuration upgrades by abstracting the option of the configuration.  Each file is a tree structure where leaves are values defined with an interpreted type.  The interpreters are defined for each meta-configuration files name *.conf.  Configuration files does not seems to interact with each other to make consistent configuration.  They provide an UI for editing their configuration file.
* [[NixOS:Properties]]
* [https://discourse.nixos.org/t/best-resources-for-learning-about-the-nixos-module-system NixOS discourse, "Best resources for learning about the NixOS module system?"]
* Debian [http://wiki.debian.org/PackageConfigUpgrade Config::Model]: target configuration upgrades by abstracting the option of the configuration.  Each file is a tree structure where leaves are values defined with an interpreted type.  The interpreters are defined for each meta-configuration files name *.conf.  Configuration files does not seems to interact with each other to make consistent configuration.  They provide an UI for editing their configuration file.


[[Category:Configuration]]
[[Category:Configuration]]
[[Category:Reference]]
[[Category:Reference]]
[[Category:NixOS]]
[[Category:NixOS]]

Revision as of 21:54, 9 June 2019

Modules are files combined by NixOS to produce the full system configuration. A module contains a Nix expression. It declares options for other modules to define (give a value). It processes them and defines options declared in other modules.[1]

For example, /etc/nixos/configuration.nix is a module. Most other modules are in nixos/modules.

Structure

Modules have the following syntax:

{
  imports = [
    # paths to other modules
  ];

  options = {
    # option declarations
  };

  config = {
    # option definitions
  };
}

There is a shorthand for modules without any declarations:

{
  require = [
    # paths to other modules
  ];

  # option definitions
}

Function

A module can be turned into a function accepting an attribute set.

{ config, pkgs, ... }:
{
  # ...
}

It may require the attribute set to contain:

config
The configuration of the entire system.
options
All option declarations refined with all definition and declaration references.
pkgs
The attribute set extracted from the Nix package collection and enhanced with the nixpkgs.config option.
modulesPath
The location of the module directory of NixOS.

Imports

Imports are paths to other NixOS modules that should be included in the evaluation of the system configuration. A default set of modules is defined in nixos/modules/module-list.nix. These don't need to be added in the import list.

Declarations

Declarations specify a module's external interfaces.

optionName = mkOption {
  # ...
}

They are created with mkOption, a function accepting a set with following attributes:[2][3]

type

The type of the option. It may be omitted, but that’s not advisable since it may lead to errors that are hard to diagnose.

default

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.

example

An example value that will be shown in the NixOS manual.

description

A textual description of the option, in DocBook format, that will be included in the NixOS manual.

Rationale

Modules were introduced to allow extending NixOS without modifying its source code.[4] They also allow splitting up configuration.nix, making the system configuration easier to maintain and to reuse.

Example

put into hello.nix in the same folder as your configuration.nix.

{ lib, pkgs, config, ... }:
with lib;                      
let
  cfg = config.services.hello;
in {
  options.services.hello = {
    enable = mkEnableOption "hello service";
    greeter = mkOption {
      type = types.string;
      default = "world";
    };
  };

  config = lib.mkIf cfg.enable {
    systemd.services.hello = {
      wantedBy = [ "multi-user.target" ];
      serviceConfig.ExecStart = "${pkgs.hello}/bin/hello -g'Hello, ${escapeShellArg cfg.greeter}!'";
    };
  };
}

Add the following to your configuration.nix

{
  imports = [ ./hello.nix ];
  ...
  services.hello = {
    enable = true;
    greeter = "Bob";
  };
}

Advanced Use Cases

Compatibility Issues with Different Nixpkgs Versions

Module options between Nixpkgs revisions can sometimes change in incompatible ways.

For example, the option services.nginx.virtualHosts.*.port in nixpkgs-17.03 was replaced by services.nginx.virtualHosts.*.listen in nixpkgs-17.09. If configuration.nix has to accommodate both variants, options can be inspected:

{ options, ... }: {
  services.nginx.virtualHosts.somehost = { /* common configuration */ }
    // (if builtins.hasAttr "port" (builtins.head options.services.nginx.virtualHosts.type.getSubModules).submodule.options
          then { port = 8000; }
          else { listen = [ { addr = "0.0.0.0"; port = 8000; } ]; });
}

Abstract imports

To import a module that's stored somewhere (but for which you have neither an absolute nor a relative path), you can use NIX_PATH elements or specialArgs from nixos/lib/eval-config.nix.

This is useful for e.g. pulling modules from a git repository without adding it as a channel, or if you just prefer using paths relative to a root you can change (as opposed to the current file, which could move in the future).

let
  inherit (import <nixpkgs> {}) writeShellScriptBin fetchgit;
  yourModules = fetchgit { ... };
in rec {
  nixos = import <nixpkgs/nixos/lib/eval-config.nix> {
    modules = [ ./configuration.nix ];
    specialArgs.mod = name: "${yourModules}/${name}";
  };

  /* use nixos here, e.g. for deployment or building an image */
}
{ config, lib, pkgs, mod, ... }: {
  imports = [
    (mod "foo.nix")
  ];

  ...
}

More complex usages

The examples below contain:

  • a child `mkOption` inherits their default from a parent `mkOption`
  • reading default values from neighbouring `mkOption`(s) for conditional defaults
  • passing in the config, to read the hostName from a submodule (email system)
  • setting default values from attrset (email system)
  • generating documentation for custom modules (outside of nixpkgs). See here

Source:

(sorry, dont' have more time to make this into a nice little guide yet, but this links should be pretty good introductions into more advanced module system usages) qknight

References

See also