How NixOS’s Atomic Generations Make System Upgrades Safe and Reproducible
NixOS atomic generations make upgrades safe by building an immutable system state and switching via the bootloader. If an update fails, you can roll back to a previous generation without manual file restoration.
03 Jul 2025, 12:30 UTC

The Problem: Rolling Back System Changes
When you update a package or tweak a configuration on a traditional Linux system, you often end up with a half‑finished state if something goes wrong. The only recourse is a manual rollback or a backup restore, both of which are error‑prone and time‑consuming. For mission‑critical machines, a single bad change can mean downtime or a security hole.
NixOS’s Declarative, Pure‑Function Approach
NixOS treats configuration.nix as a pure function: the file describes the desired system state, and the Nix compiler turns it into a set of immutable store paths under /nix/store. Because the function has no side effects, the same configuration always yields the same result, regardless of the machine it runs on. This guarantees reproducibility across deployments.
Atomic Generations and the Bootloader
When you run nixos-rebuild switch, NixOS builds a new generation of the system. The build output is stored in a new closure under /nix/store, and the bootloader (GRUB, systemd‑boot, etc.) is updated to point to that generation. The switch is all‑or‑nothing: either the new generation is activated or the previous one remains untouched. If the new generation fails to boot, the system simply boots into the last successful generation.
The bootloader keeps a list of generations in /boot/grub/grub.cfg (or the relevant entry for your bootloader). Each generation has a unique identifier, making manual selection straightforward if the GUI is unavailable.
Practical Example: Updating a Package and Rolling Back
Check current NixOS version and Nix store state:
# Verify the running release nixos-version # List existing generations systemctl list-units | grep systemd-bootModify
configuration.nixto add a new package:# /etc/nixos/configuration.nix { config, pkgs, ... }: { environment.systemPackages = with pkgs; [ <new-package> ]; }Rebuild and switch to the new generation:
# Run as root or with sudo nixos-rebuild switch --upgradeAfter the command exits, the system boots into the new generation. Verify that the package is present:
which <new-package>If the new generation fails, rollback to the previous one:
# List all generations nixos-rebuild list-generations # Roll back to the last successful generation nixos-rebuild switch --rollbackAlternatively, use the bootloader menu at startup to choose the previous generation manually.
Checking the Result
After a rollback, confirm the system state:
# Ensure the old package is still missing
which <new-package> # should return "command not found"
# Verify the generation pointer
cat /proc/cmdline | grep generation
These checks confirm that the system has reverted to the previous, known‑good state without any manual file restoration.
Trade‑offs and Disk Space Considerations
- Disk Usage: Each generation stores its entire closure in
/nix/store. Over time, old generations can accumulate, especially on systems with many updates. Runnix-collect-garbageperiodically to clean unused paths, but be careful not to remove a generation you might still want to roll back to. - Bootloader Complexity: The bootloader configuration must be kept in sync with NixOS generations. On systems with custom bootloaders or multi‑boot setups, additional care is needed to avoid pointing to a non‑existent generation.
- Version Sensitivity: Module options can change between NixOS releases. A configuration that builds on one release may require tweaks on another. Always test in a non‑production environment before deploying to critical hosts.
Actionable Takeaways
- Use
nixos-rebuild switchfor all system changes; it guarantees atomic upgrades. - Keep
configuration.nixunder version control to track changes and roll back to a known state programmatically. - Periodically run
nix-collect-garbage -dto reclaim space, but maintain at least one previous generation for safety. - Test new configurations in a VM or with
nixos-rebuild dry-runbefore applying to production.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.