Testing
How to validate changes before deploying them. The goal: catch lint, format, and evaluation errors locally so deploys to remote machines (vanessa, emily, zoe) don’t break them.
lea is the local dev workstation (x86_64-linux). Most building/testing
happens there; it can build NixOS configs natively and activate locally with
nh os switch ..
Lint and format
Section titled “Lint and format”just lint # deadnix + statixjust fmt # nixfmt over all tracked *.nix files (writes changes)just lintrunsdeadnix .(dead-code detection) thenstatix check .(anti-pattern lints). Read-only — it reports, it doesn’t fix.just fmtformats in place. The same tools run as pre-commit hooks (git-hooks-nix + treefmt-nix) and in CI.
Full check
Section titled “Full check”just checkRuns, in order:
deadnix .statix check .git ls-files '*.nix' | xargs nixfmt --check(fails if anything is unformatted — runjust fmtto fix)nix flake check
nix flake check evaluates the flake outputs: all nixosConfigurations,
darwinConfigurations, packages, devShells, and treefmt/pre-commit checks. Use
nix flake check --no-build for a faster eval-only pass that skips building
derivations.
Building / evaluating a single machine
Section titled “Building / evaluating a single machine”Build a config without activating it to confirm it compiles:
## NixOS (nh) — builds the toplevelnh os build . # current host (lea)nh os build '.#nixosConfigurations.vanessa.config.system.build.toplevel'
## Darwin (nh)nh darwin build '.#darwinConfigurations.emily.system'
## Dry-run helpers from the justfile (-n / no realisation)just build-nixos vanessajust build-darwin emilyjust build-all # emily + vanessa dry-run
## Raw nix build (produces ./result)nix build '.#nixosConfigurations.lea.config.system.build.toplevel'Eval-only (fastest — just checks the config evaluates, no build):
nix eval .#nixosConfigurations.<machine>.config.system.build.toplevel.drvPath \ --no-write-lock-filePre-deployment checklist
Section titled “Pre-deployment checklist”Before nh os switch . (local) or clan machines update <name> (remote):
just fmt— format.just lint— deadnix + statix clean.nix flake check(orjust checkfor everything at once).- Build the affected machine without activating:
- NixOS:
nh os build '.#nixosConfigurations.<machine>.config.system.build.toplevel' - Darwin:
nh darwin build '.#darwinConfigurations.<machine>.system'
- NixOS:
- If secrets changed:
clan vars generate --machine <machine>. - For a config you can’t fully trust, prefer a stage that’s easy to undo:
- NixOS:
nh os test .(activate without making it the boot default) ornh os boot .(apply on next boot only).
- NixOS:
- Deploy. If anything goes wrong, see Rollback & Recovery.
The repo also ships a just ci target (fmt + check + build-all) that
mirrors CI, and just pre-commit (stage + dry-run builds + fmt).
Helper scripts
Section titled “Helper scripts”scripts/validate-inventory.sh # sanity-check the Clan inventoryscripts/diff-machines.sh <m1> <m2> # compare two machine configsNixOS vs Darwin differences
Section titled “NixOS vs Darwin differences”| NixOS (lea, vanessa) | Darwin (emily, zoe) | |
|---|---|---|
| Build attr | nixosConfigurations.<m>.config.system.build.toplevel |
darwinConfigurations.<m>.system |
| Local build | nh os build . |
nh darwin build '.#…' |
| Local switch | nh os switch . |
nh darwin switch '.#…' |
nh os test (non-default activation) |
yes | no equivalent |
| Remote deploy | clan machines update <m> |
clan machines update <m> |
Notes:
- lea (x86_64-linux) can natively build the other NixOS machine (vanessa). Darwin
machines must build their own toplevel (cross-building Darwin from Linux isn’t
done here); rely on
nix flake checkfor eval coverage and build on the Mac. - zoe is x86_64-darwin: clan-core has dropped x86_64-darwin support, so the
devShell with the
clanCLI is unavailable there (seeflake.nixperSystem guard). Validate zoe-related changes from another host where possible. - Some packages don’t build on
aarch64-darwin— see Troubleshooting.