Skip to content

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

nix
programs.nh = {
  enable = true;
  flake = "/home/${username}/nixos-config/laptop";
  clean = {
    enable = true;
    dates = "weekly";
    extraArgs = "--keep-since 3d --keep 3";
  };
};

Rebuild Commands

bash
# Build and switch (most common)
nh os switch

# Build without switching (test)
nh os build

# Build and switch on next boot
nh os boot

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

bash
cd ~/nixos-config/laptop
nix flake update
nh os switch

To update a single input:

bash
nix flake update nixpkgs
nh os switch

Automatic 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

nix
system.autoUpgrade = {
  enable = true;
  dates = "weekly";
  flake = "/home/${username}/nixos-homelab";
  flags = [ "--upgrade-all" "--commit-lock-file" ];
};
SettingValueEffect
datesweeklyRuns once per week (systemd calendar spec)
flake/home/nixos/nixos-homelabPath to the flake on the server
--upgrade-allFlagUpdates all flake inputs before building
--commit-lock-fileFlagCommits 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:

nix
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:00

Local-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

bash
# 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 -5

Manual Server Upgrade

If you need to upgrade the server immediately without waiting for the timer:

bash
sudo nixos-rebuild switch --flake /home/nixos/nixos-homelab#homelab --upgrade-all

Flake Input Pinning

Both systems pin their inputs via flake.lock. The key difference:

AspectLaptopServer
Update triggerManual (nix flake update)Automatic (weekly timer)
Lock file commitManual (by user)Automatic (with timestamp)
Rollbacknh os switch --rollbacknixos-rebuild switch --rollback
Channelnixos-unstablenixos-unstable + nixos-25.05 (stable for some inputs)

Rollback

Laptop

bash
# 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

bash
# 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.