3.9 KiB
Nix Conventions
This document records local Nix style and design conventions.
Use these conventions when changing this flake.
Read this document with docs/dictionary.md.
Names
Reserve lib for nixpkgs.lib
Use lib only for the base nixpkgs.lib value.
Do not use lib for project functions.
Use dotfiles.lib for library functions passed through module arguments.
Use dotfiles.<name> for assembly functions passed through module arguments.
Avoid:
{
lib = dotfilesFunctions;
}
Use:
{
lib = nixpkgs.lib;
dotfiles.lib = dotfilesFunctions;
}
Name project function namespaces by role
Put pure project functions under dotfiles.lib.
Put functions that create modules, systems, or assembly values under dotfiles.
This keeps data-only functions separate from functions that carry flake context.
Avoid:
dotfiles.lib.mkHost { hostName = "neogaia"; }
Use:
dotfiles.mkHost { hostName = "neogaia"; }
File Placement
Put files in the directory that owns their role
Choose the file location before writing a Nix file.
Put assembly files under flake/.
Do not add library files until this repository has a library directory.
Put modules under modules/.
Put host configurations under hosts/<name>/.
Put host-side guest wiring under guests/.
Put registry definitions under registry/.
Keep flake.nix focused on inputs and public output wiring.
Do not add root-level Nix files other than flake.nix.
A module is self-contained configuration under modules/.
It usually scopes to one program, service, or subsystem.
Files under hosts/, guests/, and modules/ return NixOS modules.
Function Arguments
Use closed interfaces for assembly files and library files
Use exact function argument patterns for assembly files and library files. The caller owns the argument set for these files. The imported file names each accepted attribute. The imported file rejects stale or accidental extra attributes.
Avoid:
{
inputs,
lib,
self,
...
}:
Use:
{
inputs,
lib,
self,
}:
Pass function arguments explicitly
Pass only the values an assembly file or library file needs.
Bind lib to the base nixpkgs.lib value at the call site.
Use inherit only for values that keep the same name.
Avoid:
import ./flake inputs
Use:
let
inherit (nixpkgs) lib;
in
import ./flake { inherit lib inputs self; }
Keep NixOS module interfaces open
Files under hosts/, guests/, and modules/ return NixOS modules.
nixosSystem owns their argument shape.
Name each argument the module uses.
Keep ... so the module accepts standard arguments and special arguments.
Avoid:
{
config,
lib,
pkgs,
registry,
}:
Use:
{
config,
lib,
pkgs,
registry,
...
}:
let Bindings
Use role-specific binding names
A let binding name must explain the value's role in the expression.
Avoid names that describe only the value's type.
Avoid:
let
names = lib.attrNames hosts;
in
lib.genAttrs names mkHost
Use:
let
hostNames = lib.attrNames hosts;
in
lib.genAttrs hostNames mkHost
Standard Library Calls
Qualify standard library calls in flake assembly
Use qualified standard library calls inside flake assembly code.
Use lib.mapAttrs instead of inheriting mapAttrs from lib.
This keeps the source of each function visible.
Avoid:
let
inherit (lib) mapAttrs;
in
mapAttrs f attrs
Use:
lib.mapAttrs f attrs
Flake Outputs
Expose only supported flake outputs
Use public outputs for the supported interface of this flake.
Do not expose assembly functions as public outputs unless an external consumer needs them.
Keep internal functions in assembly files or dotfiles special arguments.
Avoid:
{
lib = flake;
nixosConfigurations = flake.mkHosts (self + "/hosts");
}
Use:
{
nixosConfigurations = flake.mkHosts (self + "/hosts");
}