Recovering from a failed system update: reverting flake.lock is a common way to restore a reproducible state, but it does not mean the system itself has been rolled back.
What flake.lock Really Is#
flake.lock is plain-text JSON for nix to read: nix cares about its contents, not where it came from. You can:
- Edit it manually (change rev, URL, or narHash)
- Revert it with
git checkout(the preferred option) - Copy a lock file from elsewhere
As long as narHash matches rev and the packages can be built, nix will use it.
Rollback Method One: git checkout (Preserve Current Changes First)#
If your configuration is in a git repository, prefer restoring flake.lock from a known-good Git revision:
# 1. 查看提交历史,找到更新前的 commit
cd ~/nixos-config
git status --short
# 先备份当前锁文件,保留尚未提交的更新
cp flake.lock /tmp/flake.lock.before-rollback
git log --oneline -5 flake.lock
# 2. 回退 flake.lock 到某个 commit 的版本(<known-good-commit> 是更新前)
git restore --source=<known-good-commit> -- flake.lock
# 3. 验证配置能评估(不实际构建)
nix flake check --no-build
nixos-rebuild dry-build --flake .#my-host
# 4. 检查差异;dry-build 不会构建或激活系统
git diff -- flake.lock
# 确认需要保存本次回退后再提交
git add flake.lock
git commit -m "revert(flake): roll back flake.lock to <known-good-commit>"Why this is the safest approach:
- The specified commit is a known-working version from before the update
- No need to guess narHash
- Git history provides traceability
Rollback Method Two: Roll Back the System Generation#
If the problem is in the system itself, rather than just dependency locking, you can roll back the entire generation:
# 列出所有历史系统代际(按时间倒序)
ls -l /nix/var/nix/profiles/system-*-link
# 回到上一个代际(立即生效)
sudo nixos-rebuild switch --rollback
# 回到指定代际(如第 5 个)
sudo /nix/var/nix/profiles/system-5-link/bin/switch-to-configuration switchFor the full tutorial, see the Generation Management Guide. If the new system will not boot at all, reboot and select an older generation in the GRUB menu ("NixOS - All configurations").
Garbage Collection Warning#
NixOS generations are "stacked": each switch creates a new generation, and older ones are retained until explicitly deleted. GC reclaims only store paths that are no longer referenced by roots. Do not run nix-collect-garbage before an important configuration update. Ordinary GC does not delete paths still referenced by generations; nix-collect-garbage -d deletes old generations and reclaims unreferenced content, potentially removing your rollback path.
Pitfalls of Manual Editing#
- narHash must be correct: nix uses narHash to verify downloaded content. If rev changes but narHash is still the old value, you get a
hash mismatch. Manually changing rev usually requires a corresponding new narHash. - Dedicated Commands Mean Manual Editing Is Not Always Necessary:
- Roll back to a specific commit:
在 flake.nix 中将 nixpkgs.url 固定到 github:NixOS/nixpkgs/<rev>,再运行 nix flake update nixpkgs - However, declaring inputs and letting Nix generate the lock file is usually easier to review than editing JSON manually, since the configuration itself is in a git repository.
- Roll back to a specific commit:
- flake.lock is a version lockfile: it locks each input to an exact version for reproducibility. Editing it manually means manually changing the locked version, which is entirely valid.
Operation Reference#
| Operation | Method |
|---|---|
| Revert to an older, known-good version | git restore --source=<commit> -- flake.lock (overwrites this file in the working tree; back it up first) |
| Update to the latest version | nix flake update |
| Update a single input | nix flake update nixpkgs |
| Manually change a specific rev | Edit manually, with the corresponding narHash (cumbersome; use sparingly) |
The key point: if your configuration is in a git repository, prefer restoring flake.lock from a known-good Git revision rather than editing it manually. Manual editing is more of an "advanced technique" and is usually unnecessary.
References & further reading
Adapted from technical notes. Examples use generic names.
Continue along a reading path
Flakes: project and dependency management
- 01Flake structure: inputs and outputs
- 02flake.lock and reproducibility
- 03Flake Utils and project templates
- 04External Flake references and collaboration
- 05Migrating NixOS configuration to Flakes
- 06A tutorial on Flake projects and dependency management
- 07How Flake updates work
- 08Rolling back and manually editing flake.lock