1 53 Declarative Configuration Store and Generations
Nimmo edited this page 2026-09-13 13:01:43 +01:00

Declarative Configuration, Store, and Generations

  • Type: Tutorial
  • Status: Current
  • Scope: How a nixos-config declaration becomes a build, active system, and rollback generation
  • Canonical sources: flake.nix; justfiles/deploy.just; modules/maintenance/garbage-collection.nix; modules/services/backrest.nix; Safe Testing and Deployment; Full-Host Recovery; NixOS manual
  • Last verified: Source commit 556df88494686003b1c4f20c8e0b99b5afc16a6e (2026-09-12); source HEAD b2831d33132967b4c4fb69e6068b2b05fff8fdff changes only flake.lock. Builder, validation/activation recipes, and GC policy checked 2026-09-13; no build or activation performed.
  • Review triggers: Flake builder, deployment recipes, garbage-collection policy, state/backup architecture, or upstream NixOS generation semantics

Learning goal and prerequisites

Distinguish source, evaluation, build, activation, a NixOS generation, and mutable application data. Start with the Guided Repository Tour and Nix Language Essentials. The official NixOS manual is the general reference; this lesson describes how the lifecycle appears in this fleet.

One change, several distinct states

Suppose a host changes an option in hosts/vega/default.nix or an imported service module. The .nix files declare intended configuration; they do not mutate Vega merely by being edited. flake.nix selects the host modules and pinned inputs, then Nix evaluates the merged options. A build realises a host closure—the system and its referenced store paths—without changing the running machine. This project uses:

just check
nix build .#nixosConfigurations.vega.config.system.build.toplevel --no-link

just check runs nix flake check, including the repository's formatting and updater state-machine checks. The explicit build is stronger for Vega: it constructs that host top-level, but still does not deploy it. Stage new .nix or encrypted secret files before either command because Git-backed flakes omit untracked files. Testing and CI Contracts explains the full gate selection.

The Nix store holds immutable build outputs under /nix/store. Multiple versions can coexist, and a system profile points to the chosen closure. just test builds and activates the current host without making it the next boot default; just deploy performs the reviewed deployment path. Electra's recipes preserve its current physical-hardware specialisation unless an explicit, valid mode change is requested. Never substitute generic nixos-rebuild test commands for the project wrapper when testing Electra. Use Safe Testing and Deployment for holds, canary and rollback operations rather than running activation as an exercise.

A successful switch creates a NixOS system generation, so a previous configuration can often be selected at boot or reactivated. That is a rollback of the declared system closure, not time travel for every disk. modules/maintenance/garbage-collection.nix schedules daily GC with --delete-older-than 7d; old generations are a finite rollback resource, not an indefinite archive. just generations displays recent system generations, and just build-diff compares a proposed build with the running system.

What the declaration does not capture

The pinned flake.lock and source are necessary for repeatable builds, but they do not contain live PostgreSQL/MariaDB databases, mutable web UI settings, container volumes, NAS contents, SOPS plaintext, or externally managed DNS/ingress. Even the same closure can behave differently if a mount is absent, a credential has rotated, or a service has migrated its schema. The Storage and Data Map and Network and Access Topology identify these boundaries.

Generation rollback may fail to recover an application after a database schema upgrade; it cannot undo a Disko format or recreate missing data. A stateful service needs an application-consistent backup and tested restore. Follow Backup Verification and Partial Restore or Full-Host Recovery for real recovery, not this tutorial.

Guided check

Without activating anything, find system.configurationRevision in flake.nix and explain which source revision a clean build records and why a dirty build is labelled differently. Then find the GC options in modules/maintenance/garbage-collection.nix. Answer: if you deploy a new Jellyfin module but its database is independently upgraded, which part can a previous NixOS generation restore and which part requires a data recovery plan? Verify your answer against Service Migration and Cutover.

Common mistakes: treating nix flake check as a host deployment, treating a successful host build as proof of live service health, treating a generation as a database snapshot, and assuming removing an option erases all mutable state. The next lesson, Flakes and Inputs, examines how the source and pinned dependencies enter evaluation.