This repository has been archived on 2026-08-30. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
dotfiles/docs/nix.md

237 lines
3.9 KiB
Markdown

# Nix Conventions
This document records local Nix style and design conventions.
Prefer these conventions when changing this flake.
## Names
### Reserve `lib` for `nixpkgs.lib`
Use `lib` only for the base `nixpkgs.lib` value.
Do not use `lib` for project helper functions.
Use `dotfiles.lib` for pure project helpers passed through module arguments.
Use `dotfiles.<name>` for project assembly helpers passed through module arguments.
Avoid:
```nix
{
lib = dotfilesHelpers;
}
```
Use:
```nix
{
lib = nixpkgs.lib;
dotfiles.lib = dotfilesHelpers;
}
```
## Imports
### Use closed interfaces for helper imports
Use exact function argument patterns when an imported helper file has a closed interface.
A helper file has a closed interface when the importer owns the argument set.
The imported file must name each accepted attribute.
This rejects stale or accidental extra attributes.
Avoid:
```nix
{
inputs,
lib,
self,
...
}:
```
Use:
```nix
{
inputs,
lib,
self,
}:
```
### Pass import arguments explicitly
Pass only the values an imported helper file needs.
Bind `lib` to the base `nixpkgs.lib` value at the call site.
Use `inherit` for values that keep the same name.
Avoid:
```nix
import ./flake inputs
```
Use:
```nix
import ./flake {
inherit inputs self;
lib = nixpkgs.lib;
}
```
### Keep NixOS module interfaces open
NixOS modules must accept extra arguments because the module system owns their argument shape.
Name the arguments the module uses.
Keep `...` so the module accepts standard module arguments and special arguments.
Avoid:
```nix
{
config,
lib,
pkgs,
registry,
}:
```
Use:
```nix
{
config,
lib,
pkgs,
registry,
...
}:
```
### Use `@` for forwarding wrappers
Use `@` when a wrapper must pass the complete argument set to another module function.
Name the arguments the wrapper uses before `...`.
Forward the bound argument set unchanged.
Avoid:
```nix
{ dotfiles, ... }:
dotfiles.guest { name = "sample"; } { inherit dotfiles; }
```
Use:
```nix
args@{ dotfiles, ... }:
dotfiles.guest { name = "sample"; } args
```
## `let` Bindings
### Use `let` for important intermediate values
Use a `let` binding when it names an important intermediate value.
Use a `let` binding when it avoids repeating a complex expression.
Do not use a `let` binding only to shorten a standard library call.
Avoid:
```nix
let
inherit (lib) mapAttrs;
in
mapAttrs f attrs
```
Use:
```nix
lib.mapAttrs f attrs
```
## Standard Library Calls
### Qualify standard library calls in flake assembly
Prefer qualified standard library calls inside flake assembly code.
Use `lib.mapAttrs` instead of inheriting `mapAttrs` from `lib`.
This keeps the source of helper functions visible.
Avoid:
```nix
let
inherit (lib) mapAttrs;
in
mapAttrs f attrs
```
Use:
```nix
lib.mapAttrs f attrs
```
## Flake Assembly
### Keep assembly code under `flake/`
Keep flake assembly code under `flake/`.
Keep `flake.nix` focused on inputs and public outputs.
A public output is any attribute returned by the flake `outputs` function.
Another flake can reference a public output through `inputs.<name>.<output>`.
Tools such as `nix flake show` also display public outputs.
Avoid:
```nix
# flake.nix
let
mkHosts = hostsDir: ...;
in
{
nixosConfigurations = mkHosts (self + "/hosts");
}
```
Use:
```nix
# flake.nix
let
flakeAssembly = import ./flake {
inherit inputs self;
lib = nixpkgs.lib;
};
in
{
nixosConfigurations = flakeAssembly.mkHosts (self + "/hosts");
}
```
### Expose only supported flake outputs
Use public outputs for the supported interface of this flake.
Do not expose assembly helpers as public outputs unless an external consumer needs them.
Keep internal helpers in `flake/` or `dotfiles` special arguments.
Avoid:
```nix
{
lib = flakeAssembly;
nixosConfigurations = flakeAssembly.mkHosts (self + "/hosts");
}
```
Use:
```nix
{
nixosConfigurations = flakeAssembly.mkHosts (self + "/hosts");
}
```