Day 13 — Rebuild modes & generations

Updated

July 30, 2026

Day 13 — Rebuild modes & generations

Stage II · ~4h
Goal: Master nixos-rebuild modes, system generations, and rollback—including a deliberate break and recovery on the disposable lab.

Why this day exists

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.


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

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

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

  1. test a firewall change → SSH still works →
  2. switch to commit it to boot default

Or:

  1. boot a kernel change → reboot when ready →
  2. If unbootable, select previous generation in boot menu

Theory 4 — Listing and switching generations

sudo nix-env -p /nix/var/nix/profiles/system --list-generations
# or
ls -l /nix/var/nix/profiles/system*

sudo nixos-rebuild list-generations  # when available in your version

Rollback helpers:

sudo nixos-rebuild switch --rollback
# or boot older generation from boot menu

Also:

sudo /nix/var/nix/profiles/system-<N>-link/bin/switch-to-configuration switch

Prefer 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

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 understanding
Important

Do not delete generations until you have a known good current system and understand you are dropping rollback points.


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
--update-input / flake update Separate concern (Day 24)

Worked examples bank

Example A — Safe build

cd ~/nixos-config
nixos-rebuild build --flake .#lab

Example B — test then switch

sudo nixos-rebuild test --flake .#lab
# exercise the change
sudo nixos-rebuild switch --flake .#lab

Example C — rollback

sudo nixos-rebuild switch --rollback

Lab 1 — Inventory generations before chaos

sudo nix-env -p /nix/var/nix/profiles/system --list-generations
readlink -f /nix/var/nix/profiles/system

Record current generation number in notes.


Lab 2 — Mode drills (harmless package)

  1. Add a tiny package with boot mode only.
  2. Confirm it is not on PATH until reboot (or document actual behavior you observe).
  3. Reboot (VM snapshot first).
  4. Confirm package present.

Then:

  1. Use test for another package.
  2. Confirm available immediately.
  3. Reboot without switch and observe whether it persists as default—write what happened.

Lab 3 — Deliberate break → rollback

VM snapshot first.

Introduce a recoverable break, for example:

# BAD on purpose — comment clearly
# environment.etc."BREAK".text = "…";
# or disable ssh while on console-only VM:
# services.openssh.enable = false;  # only if you have console

Safer break: set environment.systemPackages to include a typo attribute that fails eval—that is not a rollback drill. For rollback you need a successful bad generation:

environment.etc."day13-break".text = "broken intentionally";
# and something mildly annoying but not fatal, OR
# networking.firewall.allowedTCPPorts = [ ]; with ssh still via console

Better pedagogical break:

  1. switch a config that installs a known package cowsay.
  2. Then switch a config that removes it and sets environment.variables.DAY13 = "broken";.
  3. rollback and show cowsay/env difference.

Or classic:

sudo nixos-rebuild switch --flake .#lab
# introduce change that succeeds but you dislike
sudo nixos-rebuild switch --rollback

Document generation numbers before/after.


Lab 4 — Boot menu literacy

On next reboot:

  1. Enter boot loader menu (often hold space / show menu for systemd-boot).
  2. Identify generation entries.
  3. Boot current known-good.

Write how your hypervisor + loader expose this.


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: …

Common gotchas

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

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

Commit

cd ~/nixos-config
git add .
git commit -m "day13: rebuild modes generations rollback card"

Tomorrow

Day 14 — Users & access. Declarative users, wheel/sudo, and SSH keys only for remote admin habits.