Nix and NixOS Version Reference
A structured reference for Boring-NixOS readers tracking which Nix CLI features and NixOS system options became available in each release. Coverage spans Nix 2.18 – 2.35 and NixOS 23.05 – 26.05. This book’s examples target Nix 2.35 and NixOS 26.05 “Yarara”. Earlier rows are history so you can read old flakes.
Each section contains a table of reader-relevant changes followed by one short runnable example that exercises the most impactful addition in that release. All examples assume the infrastructure desk scenario: a shared flake that builds team tooling and drives a set of NixOS workstations.
Nix CLI Releases
Nix 2.18
| Area | Change |
|---|---|
nix flake metadata |
Prints flake description, inputs, and their resolved URLs; last-modified timestamp now shown per input. |
--log-format |
Accepts raw, internal-json, bar, bar-with-logs; useful for CI pipelines that consume structured output. |
| Evaluator | builtins.fetchTree no longer fetches tarballs eagerly when the hash is already in the store. |
| Error messages | Multi-line errors now include a source excerpt with a caret pointing at the offending token. |
Key feature — nix flake metadata
Save as show-meta.sh:
# show-meta.sh
nix flake metadata \
--log-format bar \
github:NixOS/nixpkgs/nixos-26.05Run:
bash show-meta.shOutput:
Resolved URL: github:NixOS/nixpkgs/nixos-26.05
Locked URL: github:NixOS/nixpkgs/a1b2c3d4e5f6...
Description: Nix Packages collection & NixOS
Path: /nix/store/xxxxxxxx-source
Last modified: 2024-11-30 12:00:00
Inputs:
└───nixpkgs: (this flake)
Nix 2.19
| Area | Change |
|---|---|
nix store gc |
Replaces nix-collect-garbage progressively; supports --max-freed <bytes> to cap space reclaimed per run. |
nix store gc --dry-run |
Reports paths that would be deleted without touching the store. |
nix profile |
nix profile diff-closures added; shows package diff between two profile generations. |
| Daemon | Store lock contention reduced for concurrent multi-user builds. |
Key feature — nix store gc --dry-run
Save as gc-preview.sh:
# gc-preview.sh
# Preview how much the desk workstation store can shrink
# before committing to deletion.
nix store gc --dry-run --max-freed $((10 * 1024 * 1024 * 1024))Run:
bash gc-preview.shOutput:
Would delete: /nix/store/aaa...-old-toolchain-2023
Would delete: /nix/store/bbb...-devshell-2023-11
...
Would free 7.4 GiB (limit was 10.0 GiB)
Nix 2.20
| Area | Change |
|---|---|
nix flake archive |
Copies all flake inputs into a binary cache or a local store, enabling fully offline evaluation afterwards. |
nix flake archive --to |
Accepts file:///path, s3://bucket, or ssh://host as destination. |
nix copy |
--substitute-on-destination flag added; destination fetches missing paths from its own substituters before failing. |
| Build sandbox | Linux sandbox now mounts /proc as tmpfs by default, improving isolation. |
Key feature — nix flake archive to a local mirror
Save as archive-inputs.sh:
# archive-inputs.sh
# Snapshot all flake inputs into a local binary cache so the
# desk's air-gapped build box can evaluate without internet.
nix flake archive \
--to file:///srv/nix-cache \
/home/ops/desk-infraRun:
bash archive-inputs.shOutput:
archiving input 'nixpkgs'
/nix/store/xxxxxxxx-source → file:///srv/nix-cache
archiving input 'home-manager'
/nix/store/yyyyyyyy-source → file:///srv/nix-cache
done — 2 inputs archived
Nix 2.21
| Area | Change |
|---|---|
nix eval --apply |
Applies a Nix function to the evaluated result before printing; enables one-liner transformations. |
nix eval --json |
Now handles null and true/false correctly in all output formatters. |
nix flake update |
--commit-lock-file flag commits the updated flake.lock with a machine-generated commit message. |
| Repl | :reload re-reads the current file without restarting the session. |
Key feature — nix eval --apply
Save as list-packages.sh:
# list-packages.sh
# Print just the names of packages exposed by the desk flake
# without writing a separate script.
nix eval \
/home/ops/desk-infra#packages.x86_64-linux \
--apply 'pkgs: builtins.attrNames pkgs' \
--jsonRun:
bash list-packages.shOutput:
["desk-tools","lint-runner","release-packager"]Nix 2.22
| Area | Change |
|---|---|
nix build --rebuild |
Rebuilds a derivation even if its output is in the store, then compares the new result to the cached one — a fast reproducibility check. |
nix copy --from / --to |
Both flags marked stable; no longer experimental. |
nix flake check |
Reports unfree license violations when --allow-unfree is absent. |
| Evaluator | builtins.readFileType added: returns "regular", "directory", "symlink", or "unknown". |
Key feature — nix build --rebuild
Save as verify-repro.sh:
# verify-repro.sh
# Rebuild the desk tool and confirm the output hash is stable.
# A mismatch here means a non-deterministic build is lurking.
nix build \
/home/ops/desk-infra#packages.x86_64-linux.desk-tools \
--rebuildRun:
bash verify-repro.shOutput (reproducible):
warning: performing a check build
[3/0/1 built] building desk-tools-1.4.0...
/nix/store/abc123...-desk-tools-1.4.0 (deterministic ✓)
Output (non-reproducible):
warning: performing a check build
error: derivation '/nix/store/...-desk-tools-1.4.0.drv' may not
be deterministic: output '/nix/store/abc123...' differs
from '/nix/store/def456...'
Nix 2.23
| Area | Change |
|---|---|
| Lazy trees | Flake inputs are fetched only when their subtree is actually evaluated; large monorepo inputs no longer block evaluation. |
nix fmt |
Declared stable; runs the formatter specified in flake.nix formatter output. |
nix repl :doc |
Prints the docstring attached to any Nix function or built-in. |
nix repl :log |
Shows the build log for a derivation path without leaving the REPL. |
nix flake update |
Accepts multiple named inputs: nix flake update nixpkgs home-manager. |
Key feature — nix fmt enforced in CI
Save as fmt-check.sh:
# fmt-check.sh
# Fail CI if any Nix file in the desk flake needs reformatting.
nix fmt /home/ops/desk-infra -- --checkRun:
bash fmt-check.shOutput (clean):
All Nix files already formatted.
Output (needs formatting):
Would reformat: /home/ops/desk-infra/modules/workstation.nix
error: 1 file would be reformatted
Nix 2.24
| Area | Change |
|---|---|
nix path-info --json |
Output is now a structured JSON array with path, narHash, narSize, references, registrationTime, and deriver fields. |
nix flake check |
Checks nixosConfigurations, darwinConfigurations, and homeConfigurations outputs for module evaluation errors. |
nix store diff-closures |
Declared stable; compares the full runtime closure of two store paths and reports added/removed/changed paths. |
nix build --print-build-logs |
Default changed to true in interactive terminals. |
Key feature — nix store diff-closures
Save as diff-release.sh:
# diff-release.sh
# Compare the desk-tools closure between the last release and
# HEAD so the team knows exactly what changed before shipping.
OLD=$(nix build \
"/home/ops/desk-infra?ref=v1.3.0#packages.x86_64-linux.desk-tools" \
--no-link --print-out-paths)
NEW=$(nix build \
/home/ops/desk-infra#packages.x86_64-linux.desk-tools \
--no-link --print-out-paths)
nix store diff-closures "$OLD" "$NEW"Run:
bash diff-release.shOutput:
desk-tools: 1.3.0 → 1.4.0
openssl: 3.2.1 → 3.2.2 (+12 KiB)
python3: 3.11.8 → 3.12.3 (+1.1 MiB)
curl: (unchanged)
added: zlib 1.3.1