NixOS modules: Difference between revisions
imported>Malteneuss m Add imports vs import note which trips ups beginners often |
VTimofeenko (talk | contribs) →Function: expand the description of the module arguments |
||
(14 intermediate revisions by 10 users not shown) | |||
Line 1: | Line 1: | ||
'''Modules''' | NixOS produces a full system configuration by combining smaller, more isolated and reusable components: '''Modules'''. A module is a file containing a Nix expression with a specific structure. 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> | ||
For example, {{ic|/etc/nixos/configuration.nix}} is a module. Most other modules are in {{Nixpkgs Link|nixos/modules}}. | For example, {{ic|/etc/nixos/configuration.nix}} is a module. Most other modules are in {{Nixpkgs Link|nixos/modules}}. | ||
Line 10: | Line 10: | ||
{ | { | ||
imports = [ | imports = [ | ||
# | # Paths to other modules. | ||
# Compose this module out of smaller ones. | |||
]; | ]; | ||
options = { | options = { | ||
# option | # Option declarations. | ||
# Declare what settings a user of this module can set. | |||
# Usually this includes a global "enable" option which defaults to false. | |||
}; | }; | ||
config = { | config = { | ||
# option | # Option definitions. | ||
# Define what other settings, services and resources should be active. | |||
# Usually these depend on whether a user of this module chose to "enable" it | |||
# using the "option" above. | |||
# Options for modules imported in "imports" can be set here. | |||
}; | }; | ||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
There is a shorthand for modules without any declarations: | There is a shorthand for modules without any option declarations: | ||
<syntaxhighlight lang="nix"> | <syntaxhighlight lang="nix"> | ||
{ | { | ||
imports = [ | imports = [ | ||
# | # Paths to other modules. | ||
./module.nix | ./module.nix | ||
/path/to/absolute/module.nix | /path/to/absolute/module.nix | ||
]; | ]; | ||
# | # Config definitions. | ||
services.othermodule.enable = true; | |||
# ... | |||
# Notice that you can leave out the "config { }" wrapper. | |||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
Note that despite the name, <code>imports = [./module.nix]</code> should not be confused with the Nix [https://nixos.org/manual/nix/stable/language/builtins.html#builtins-import builtins] function <code>import module.nix</code>. | |||
<code>imports</code> expects a path to a file containing a NixOS module structured as described here. <code>import</code> can load arbitrary Nix expression from provided file with no expectation of structure. (no expected structure). See [https://discourse.nixos.org/t/import-list-in-configuration-nix-vs-import-function/11372/8 this post] for more details. | |||
Note: <code>imports</code> provides the same behavior as the obsolete <code>require</code>. There is no reason to use <code>require</code> anymore, however it may still linger in some legacy code. | Note: <code>imports</code> provides the same behavior as the obsolete <code>require</code>. There is no reason to use <code>require</code> anymore, however it may still linger in some legacy code. | ||
Line 43: | Line 55: | ||
=== Function === | === Function === | ||
A module | A module may be a function accepting an attribute set. | ||
<syntaxhighlight lang="nix"> | <syntaxhighlight lang="nix"> | ||
{ config, pkgs, ... }: | { config, pkgs, ... }: | ||
{ | { | ||
imports = []; | |||
# ... | # ... | ||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
Following arguments are available in NixOS modules by default: | |||
<dl> | <dl> | ||
Line 61: | Line 74: | ||
<dt><code>options</code></dt> | <dt><code>options</code></dt> | ||
<dd>All option declarations refined with all definition and declaration references.</dd> | <dd>All option declarations refined with all definition and declaration references.</dd> | ||
<dt><code>lib</code></dt> | |||
<dd>An instance of the nixpkgs "standard library", providing what usually is in <code>pkgs.lib</code>.</dd> | |||
<dt><code>pkgs</code></dt> | <dt><code>pkgs</code></dt> | ||
Line 68: | Line 84: | ||
<dd>The location of the <code>module</code> directory of NixOS.</dd> | <dd>The location of the <code>module</code> directory of NixOS.</dd> | ||
</dl> | </dl>The "<code>...</code>" part of the argument attribute set indicates that this module does not depend on the rest of the arguments. When the module is defined as a function, this pattern is typically required, otherwise the evaluation will fail citing unexpected arguments. | ||
==== Passing custom values to modules ==== | |||
The [[NixOS:config_argument|<code>config</code>]], <code>options</code>, <code>lib</code>, <code>pkgs</code>, and <code>modulesPath</code> arguments are passed automatically to modules, when the module is imported. | |||
For example, in the following Nix flake, the `./configuration.nix` file will be provided with the default set of arguments listed above, plus `extraArg`, which was set in the `specialArgs` argument to the `nixosGenerate` function.<syntaxhighlight lang="nix"> | |||
{ | |||
inputs = { | |||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-23.11"; | |||
nixos-generators = { | |||
url = "github:nix-community/nixos-generators"; | |||
inputs.nixpkgs.follows = "nixpkgs"; | |||
}; | |||
xc = { | |||
url = "github:joerdav/xc"; | |||
inputs.nixpkgs.follows = "nixpkgs"; | |||
}; | |||
}; | |||
outputs = { nixpkgs, nixos-generators, xc, ... }: | |||
let | |||
pkgsForSystem = system: import nixpkgs { | |||
inherit system; | |||
overlays = [ | |||
(final: prev: { xc = xc.packages.${system}.xc; }) | |||
]; | |||
}; | |||
allVMs = [ "x86_64-linux" "aarch64-linux" ]; | |||
forAllVMs = f: nixpkgs.lib.genAttrs allVMs (system: f { | |||
inherit system; | |||
pkgs = pkgsForSystem system; | |||
}); | |||
in | |||
{ | |||
packages = forAllVMs ({ system, pkgs }: { | |||
vm = nixos-generators.nixosGenerate { | |||
system = system; | |||
specialArgs = { | |||
extraArg = "foobar"; | |||
}; | |||
modules = [ | |||
./configuration.nix | |||
]; | |||
format = "raw"; | |||
}; | |||
}); | |||
}; | |||
} | |||
</syntaxhighlight> | |||
==== modulesPath ==== | ==== modulesPath ==== | ||
Line 116: | Line 180: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
They are created with {{ic|mkOption}}, a function accepting a set with following attributes:<ref>{{Nixpkgs Link|lib/options.nix# | They are created with {{ic|mkOption}}, a function accepting a set with following attributes:<ref>{{Nixpkgs Link|lib/options.nix#L66-L88}}</ref><ref>{{manual:nixos|sec=#sec-option-declarations|chapter=42.1. Option Declarations}}</ref> | ||
<dl> | <dl> | ||
Line 149: | Line 213: | ||
== Example == | == Example == | ||
put | To see how modules are setup and reuse other modules in practice put <code>hello.nix</code> in the same folder as your <code>configuration.nix</code>: | ||
<syntaxhighlight lang="nix"> | <syntaxhighlight lang="nix"> | ||
{ lib, pkgs, config, ... }: | { lib, pkgs, config, ... }: | ||
with lib; | with lib; | ||
let | let | ||
# Shorter name to access final settings a | |||
# user of hello.nix module HAS ACTUALLY SET. | |||
# cfg is a typical convention. | |||
cfg = config.services.hello; | cfg = config.services.hello; | ||
in { | in { | ||
# Declare what settings a user of this "hello.nix" module CAN SET. | |||
options.services.hello = { | options.services.hello = { | ||
enable = mkEnableOption "hello service"; | enable = mkEnableOption "hello service"; | ||
Line 164: | Line 233: | ||
}; | }; | ||
# Define what other settings, services and resources should be active IF | |||
# a user of this "hello.nix" module ENABLED this module | |||
# by setting "services.hello.enable = true;". | |||
config = mkIf cfg.enable { | config = mkIf cfg.enable { | ||
systemd.services.hello = { | systemd.services.hello = { | ||
Line 173: | Line 245: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
The other <code>configuration.nix</code> module can then import this <code>hello.nix</code> module | |||
and decide to enable it (and optionally set other allowed settings) as follows: | |||
<syntaxhighlight lang=nix> | <syntaxhighlight lang=nix> | ||
{ | { | ||
Line 324: | Line 398: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
If you're developing on top of master, this will potentially cause the compilation of lots of packages, since changes on master might not cached on cache.nixos.org yet. To avoid that, you can develop your module on top of the <code>nixos-unstable</code> [[ | If you're developing on top of master, this will potentially cause the compilation of lots of packages, since changes on master might not cached on cache.nixos.org yet. To avoid that, you can develop your module on top of the <code>nixos-unstable</code> [[Channel branches|channel branch]], tracked by the eponymous branch in https://github.com/NixOS/nixpkgs: | ||
<syntaxhighlight lang="bash"> | <syntaxhighlight lang="bash"> | ||
git checkout -b mymodule upstream/nixos-unstable | git checkout -b mymodule upstream/nixos-unstable | ||
</syntaxhighlight> | </syntaxhighlight> | ||
=== With Flakes === | |||
If you're developing a module from nixpkgs, you can try and follow the directions here: https://github.com/Misterio77/nix-starter-configs/issues/28. | |||
If you want to develop a module from a git repo, you can use `--override-input`. For example, if you have an input in your flake called {{ic|jovian}},, you can use | |||
<syntaxhighlight lang="bash"> | |||
nixos-rebuild switch --override-input jovian <path-to-url>` --flake <uri> | |||
</syntaxhighlight> | |||
Of course, it doesn't have to be {{|c|nixos-rebuild}} in particular. | |||
== References == | == References == |