Updates & Upgrades
The laptop and server have different update strategies reflecting their usage patterns.
Laptop: Manual Updates with nh
The laptop uses nh, a NixOS helper that wraps nixos-rebuild with a better interface.
Source: laptop/modules/nh.nix
programs.nh = {
enable = true;
flake = "/home/${username}/nixos-config/laptop";
clean = {
enable = true;
dates = "weekly";
extraArgs = "--keep-since 3d --keep 3";
};
};Rebuild Commands
# Build and switch (most common)
nh os switch
# Build without switching (test)
nh os build
# Build and switch on next boot
nh os bootnh automatically detects the flake path from the config, so no --flake argument is needed.
Updating Inputs
To pull the latest versions of all flake inputs:
cd ~/nixos-config/laptop
nix flake update
nh os switchTo update a single input:
nix flake update nixpkgs
nh os switchAutomatic Cleanup
nh automatically cleans old generations weekly:
- Keeps generations from the last 3 days
- Keeps at least 3 generations regardless of age
- Runs as a systemd timer
Server: Automatic Upgrades
The server upgrades itself automatically on a weekly schedule.
Source: server/modules/auto-upgrade.nix
system.autoUpgrade = {
enable = true;
dates = "weekly";
flake = "/home/${username}/nixos-homelab";
flags = [ "--upgrade-all" "--commit-lock-file" ];
};| Setting | Value | Effect |
|---|---|---|
dates | weekly | Runs once per week (systemd calendar spec) |
flake | /home/nixos/nixos-homelab | Path to the flake on the server |
--upgrade-all | Flag | Updates all flake inputs before building |
--commit-lock-file | Flag | Commits the updated flake.lock to the repo |
Post-Upgrade Git Amend
After the upgrade succeeds, a custom ExecStartPost amends the lock file commit with a timestamped message:
systemd.services.nixos-upgrade.serviceConfig.ExecStartPost = lib.mkAfter ''
cd /home/${username}/nixos-homelab
git commit --amend -m "AUTO UPDATE $(date -Iseconds)" --no-edit || true
'';This produces commits like:
AUTO UPDATE 2026-02-28T03:00:00+00:00Local-Only Commits
The auto-upgrade commits to the local repository on the server. These commits are not pushed to any remote. If you need to sync, pull from the server manually.
Monitoring Upgrades
# Check the timer schedule
systemctl list-timers nixos-upgrade.timer
# View the last upgrade log
journalctl -u nixos-upgrade.service -b
# Check current system generation
nixos-rebuild list-generations | head -5Manual Server Upgrade
If you need to upgrade the server immediately without waiting for the timer:
sudo nixos-rebuild switch --flake /home/nixos/nixos-homelab#homelab --upgrade-allFlake Input Pinning
Both systems pin their inputs via flake.lock. The key difference:
| Aspect | Laptop | Server |
|---|---|---|
| Update trigger | Manual (nix flake update) | Automatic (weekly timer) |
| Lock file commit | Manual (by user) | Automatic (with timestamp) |
| Rollback | nh os switch --rollback | nixos-rebuild switch --rollback |
| Channel | nixos-unstable | nixos-unstable + nixos-25.05 (stable for some inputs) |
Rollback
Laptop
# Roll back to the previous generation
nh os switch --rollback
# Or select a specific generation at boot via systemd-boot menu
# (Lanzaboote signs all generations)Server
# Roll back to the previous generation
sudo nixos-rebuild switch --rollback
# Or boot into a previous generation via systemd-boot
# (configurationLimit = 5, so last 5 generations are available)Impermanence and Rollback
Rolling back a NixOS generation on the server only affects the system configuration (packages, services, etc.). Persistent data in /persist is not affected. The root filesystem is wiped on every boot regardless of which generation is active.