Rebuild modes and generations
Rebuild modes and generations
Goal: Master nixos-rebuild modes, system generations, and rollback—including a deliberate break and recovery on the disposable lab.
Why this chapter matters
NixOS’s famous safety is not automatic—it is generational profiles + boot entries + knowing which rebuild verb you used. Without that theory, “rollback” is folklore.
Ops motivation: production incidents need a rehearsed rollback card. This chapter builds that muscle on a disposable VM so production is not your first practice.
Theory 1 — System profile and generations
NixOS points the running system at a profile:
/nix/var/nix/profiles/system → system-N-link → store path
Each successful deployment can add a generation N. Boot loaders list generations so you can boot an older one when the new world is wrong.
| Concept | Meaning |
|---|---|
| Generation | A complete system closure you can activate/boot |
| Current | What the profile points at now |
| Rollback | Point profile (and/or boot default) at older generation |
Inspect
sudo nix-env -p /nix/var/nix/profiles/system --list-generations
readlink -f /nix/var/nix/profiles/system
ls -l /nix/var/nix/profiles/system*Theory 2 — Rebuild modes
sudo nixos-rebuild <mode> --flake .#lab| Mode | Effect |
|---|---|
switch |
Build + activate now + set boot default to new gen |
boot |
Build + set boot default; do not activate until reboot |
test |
Build + activate now; do not change boot default |
build |
Build only; no activation |
dry-activate |
Show activation plan (when supported/useful) |
build-vm |
Build a VM of the config (extra workflows) |
Choosing modes
| Situation | Prefer |
|---|---|
| Normal daily change | switch |
| Risky change; want easy reboot escape | test first or boot |
| Remote SSH-only host | Extra care—bad switch can lock you out |
| CI / check | build |
| Kernel/boot experiments | boot then reboot deliberately |
Remote note
If you break networking/SSH on a remote machine with switch, you may need console. Lab VMs have consoles—use them.
Theory 3 — Activation vs boot default
test: running config changes; reboot may return to previous default
switch: running + default updated
boot: default updated; running stays old until reboot
Worked story
testa firewall change → SSH still works →
switchto commit it to boot default
Or:
boota kernel change → reboot when ready →
- If unbootable, select previous generation in boot menu
Decision flowchart
Is the change network/SSH sensitive?
yes → prefer test (with console available) → switch
Is the change kernel/bootloader?
yes → consider boot → reboot → verify
Otherwise → switch
Want no activation? → build
Theory 4 — Listing and switching generations
sudo nix-env -p /nix/var/nix/profiles/system --list-generations
# or
sudo nixos-rebuild list-generations # when available in your versionRollback helpers:
sudo nixos-rebuild switch --rollback
# or boot older generation from boot menuAlso:
sudo /nix/var/nix/profiles/system-<N>-link/bin/switch-to-configuration switchPrefer documented nixos-rebuild interfaces when possible.
Theory 5 — What is not rolled back
| Rolled back with system gen | Not rolled back |
|---|---|
| Packages, units, users declared in config | Your data in /home, /var |
Most /etc files managed by NixOS |
Databases, untracked files |
| Kernel (for that gen) | Out-of-band disk edits |
| Firewall rules from config | Manual live nft edits as SoT (don’t) |
Punchline: rollback restores system closure, not time-travel for application data.
Theory 6 — GC and generations
Old generations root large closures. Cleaning:
sudo nix-collect-garbage -d # deletes old profile gens — careful
sudo nixos-rebuild … # after understandingDo not delete generations until you have a known good current system and understand you are dropping rollback points.
| Action | Risk |
|---|---|
| Keep last N gens | Disk vs safety trade |
| GC after known-good deploy | Frees space |
| GC before verifying | Removes escape hatches |
Theory 7 — Flake + rebuild flags worth knowing
sudo nixos-rebuild switch --flake .#lab
sudo nixos-rebuild switch --flake .#lab --show-trace
sudo nixos-rebuild switch --flake .#lab -L
sudo nixos-rebuild switch --flake path:/home/you/nixos-config#lab| Flag | Use |
|---|---|
--show-trace |
Eval errors |
-L |
Build logs |
--impure |
Avoid unless you know why |
--upgrade / channel habits |
Prefer flake lock updates instead |
Lock updates are a separate concern (Home and flake layout part).
Theory 8 — Activation scripts and failure modes
Activation runs scripts that update bootloader entries, restart units, rewrite /etc, etc.
| Failure class | Response |
|---|---|
| Eval | No new gen; fix Nix |
| Build | No activation; fix package |
| Activation partial | Read output; may need rollback/console |
| Unit failed | systemctl, journal; gen may still be current |
test is valuable because reboot can abandon a bad experiment if boot default never moved.
Theory 9 — Naming generations in ops notes
Track in docs/rollback.md:
| Field | Example |
|---|---|
| Last known good gen | 12 |
| Last change summary | “opened ssh + htop” |
| Snapshot name | pre-firewall |
Generations numbers alone are not memory—annotate them.
Worked examples bank
Example A — Safe build
cd ~/nixos-config
nixos-rebuild build --flake .#labExample B — test then switch
sudo nixos-rebuild test --flake .#lab
# exercise the change
sudo nixos-rebuild switch --flake .#labExample C — rollback
sudo nixos-rebuild switch --rollbackExample D — Compare generations (conceptual)
ls -l /nix/var/nix/profiles/system-*-link | tail
# note store paths differ per generationExample E — Logs during rebuild
sudo nixos-rebuild switch --flake .#lab -L --show-traceLab 1 — Inventory generations before chaos
sudo nix-env -p /nix/var/nix/profiles/system --list-generations
readlink -f /nix/var/nix/profiles/systemRecord current generation number in notes.
Lab 2 — Mode drills (harmless package)
- Add a tiny package with
bootmode only.
- Confirm it is not on PATH until reboot (or document actual behavior you observe).
- Reboot (VM snapshot first).
- Confirm package present.
Then:
- Use
testfor another package.
- Confirm available immediately.
- Reboot without
switchand observe whether it persists as default—write what happened.
Lab 3 — Deliberate break → rollback
VM snapshot first.
Pedagogical break:
switcha config that installs a known packagecowsay.
- Then
switcha config that removes it and sets a harmless env marker.
rollbackand show package/env difference.
Document generation numbers before/after.
Safer annoying-but-not-fatal changes beat eval failures (eval never creates a “bad generation”).
Lab 5 — Incident card
Create ~/nixos-config/docs/rollback.md:
# Rollback card
1. Console access method: …
2. List generations: …
3. Rollback command: …
4. Boot menu steps: …
5. Last known good generation: …Exercises
- Fill a table: mode × (activates now?) × (changes boot default?).
- Perform
buildthen inspect toplevel path without switching.
- Simulate remote-only caution: list changes you would only
testfirst.
- After three switches, list gens and mark which you could GC later.
- Break SSH in a snapshotted VM; recover via console + rollback.
- Time a no-op rebuild vs a package-adding rebuild.
- Document difference between profile rollback and boot-menu boot.
- Add a “last good gen” field to your git commit message habit.
- Explain to a peer why DB data survives rollback (or doesn’t get restored).
- Practice absolute flake path rebuild under sudo.
- Read activation output for one switch; annotate three steps.
- Update rollback card after the boot chapter for loader keys.
Common pitfalls
| Symptom | Theory |
|---|---|
| Rollback “did nothing” for app data | Data ≠ system gen |
| Locked out via SSH | Use console; prefer test for net changes |
| No older generations | GC’d or first install |
test change vanished after reboot |
Expected if never switched |
| Flake path wrong under sudo | Use absolute path or root’s cwd discipline |
| Eval error mistaken for rollback drill | Need a successful bad generation |
| GC before verification | Lost escape hatches |
Checkpoint
- Explain switch/test/boot/build
- List system generations
- Performed a rollback successfully
- Boot menu generation selection documented
- Incident card written
- VM snapshot restored option still available
Further depth (this book)
| Topic | Chapter |
|---|---|
| Firewall safety with test | Networking and firewall |
| Boot loader entries | Boot and hardware |
| State vs generations | Filesystems and state |
| GC hygiene fleet-wide | Ops part |