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.8 KiB
Markdown

# Nix Conventions
This document records local Nix style and design conventions.
Use 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 for helper imports with closed interfaces.
A helper import has a closed interface when the caller owns the argument set.
The imported file names each accepted attribute.
It 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 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 passes 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 repeated complex expressions.
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
Use 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.
The `outputs` function returns each public output as an attribute.
An external flake reads public outputs through `inputs.<name>.<output>`.
`nix flake show` also displays 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");
}
```