Nix Module
A NixOS module is just a Nix expression that at most declares:
- Options — the configuration schema (types, defaults, docs).
- Config — how those options are turned into system state (systemd units, config files, package installs, etc.).
Modules are merged together at evaluation time into one big configuration.
Structure
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.services.myapp;
in {
#### 1. Options ####
options.services.myapp = {
enable = mkOption {
type = types.bool;
default = false;
description = "Whether to enable MyApp.";
};
package = mkOption {
type = types.package;
default = pkgs.myapp;
description = "The package to use for MyApp.";
};
settings = mkOption {
type = types.attrs;
default = {};
description = "Configuration written to /etc/myapp.conf.";
};
};
#### 2. Config ####
config = mkIf cfg.enable {
# Ensure package is available
environment.systemPackages = [ cfg.package ];
# Write configuration file
environment.etc."myapp.conf".text =
lib.generators.toKeyValue {} cfg.settings;
# Create a systemd service
systemd.services.myapp = {
description = "MyApp Service";
wantedBy = [ "multi-user.target" ];
serviceConfig = {
ExecStart = "${cfg.package}/bin/myapp --config /etc/myapp.conf";
Restart = "always";
};
};
};
}Assertions
You can add which have to evaluate to true in order to successfully build.
Using this you can make sure there are no invariants of your configuration.
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.services.myapp;
in {
options.services.myapp = {
...
};
config = mkIf cfg.enable {
...
# Assertions
assertions = [
{
assertion = (cfg.myoption != null);
message = "This option cant be null"
}
];
};
}Options
Use the mkOption function to declare options:
mkOption {
# Optional default value used when no definition is given in the configuration.
default ? null,
# Substitute for documenting the default, if evaluating the default value during documentation rendering is not possible.
defaultText ? null,
# Optional example value used in the manual.
example ? null,
# Optional string describing the option. This is required if option documentation is generated.
description ? null,
# Optional option type, providing type-checking and value merging.
type ? null,
# Optional function that converts the option value to something else.
apply ? null,
# Optional boolean indicating whether the option is for NixOS developers only.
internal ? null,
# Optional, whether the option and/or sub-options show up in the manual.
visible ? null,
# Optional boolean indicating whether the option can be set only once.
readOnly ? null,
}For declaring a enable option there is a mkEnableOption helper.
Types
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. There are many more but here are some basic types:
Basic
types.attrs: A free-form attribute set.types.bool: A boolean, its values can betrueorfalse.types.path: 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 specifictypes.packageshould be preferred.types.package: A derivation or a store path.
Numbers
types.int: A signed integer.types.ints.{s8, s16, s32}: Signed integers with a fixed length (8, 16 or 32 bits). They go from −2n/2 to 2n/2−1 respectively (e.g. −128 to 127 for 8 bits).types.ints.unsigned: An unsigned integer (that is >= 0).types.ints.{u8, u16, u32}: Unsigned integers with a fixed length (8, 16 or 32 bits). They go from 0 to 2n−1 respectively (e.g. 0 to 255 for 8 bits).types.ints.positive: A positive integer (that is > 0).types.port: A port number. This type is an alias totypes.ints.u16 <None>_.
Text
types.str: A string. Multiple definitions cannot be merged.types.lines: A string. Multiple definitions are concatenated with a new line “\n”.types.commas: A string. Multiple definitions are concatenated with a comma ”,“.types.envVar: A string. Multiple definitions are concatenated with a collon ”:“.types.strMatching: A string matching a specific regular expression. Multiple definitions cannot be merged. The regular expression is processed usingbuiltins.match.
Variants
types.enum l: One element of the listl, e.g.types.enum [ "left" "right" ]. Multiple definitions cannot be merged.types.separatedString sep: A string with a custom separator sep, e.g.types.separatedString "\|".types.ints.between lowest highest: An integer between lowest and highest (both inclusive). Useful for creating types like types.port.types.submodule o: A set of sub optionso.ocan 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 totypes.submoduleWith { modules = toList o; shorthandOnlyDefinesConfig = true; }.types.submoduleWith { modules, specialArgs ? {}, shorthandOnlyDefinesConfig ? false }: Liketypes.submodule, but more flexible and with better defaults.
Composed Types
Composed types are types that take a type as parameter. listOf int and either int str are examples of composed types.
types.listOf t: A list ofttype, e.g.types.listOf int. Multiple definitions are merged with list concatenation.types.attrsOf t: An attribute set of where all the values are ofttype. Multiple definitions result in the joined attribute set.types.lazyAttrsOf t: An attribute set of where all the values are ofttype. Multiple definitions result in the joined attribute set. This is the lazy version oftypes.attrsOf, allowing attributes to depend on each other.types.loaOf t: An attribute set or a list of t type. Multiple definitions are merged according to the value.types.nullOr t:nullor typet. Multiple definitions are merged according to typet.types.uniq t: Ensures that type t cannot be merged. It is used to ensure option definitions are declared only once.types.either t1 t2: Typet1or typet2, e.g.with types; either int str. Multiple definitions cannot be merged.types.oneOf [ t1 t2 … ]: Typet1or typet2and so forth, e.g.with types; oneOf [ int str bool ]. Multiple definitions cannot be merged.types.coercedTo from f to: Typetoor type from which will be coercedtotype to using functionfwhich takes an argument of typefromand return a value of typeto.