NixOS syllabus
Syllabus — expert path for Nix & NixOS
Status: Canonical outline for Sub-book 2 (also aligned with standalone monorepo book NixOS).
Baseline: Nix 2.34.x · NixOS / nixpkgs 26.05 “Yarara”.
Voice: Journey notebook. Ordering: expert pedagogy, not a merge of calendars.
Chapters follow this path. Source documents supply topics and exercises; they do not override the sequence below.
Why this order (expert rationale)
Nix rewards tight feedback loops. Long theory blocks before a real rebuild create fragile knowledge. Production NixOS work in 2026 is overwhelmingly flake-pinned, module-composed, and generation-rollback based. The path below matches that world.
| Principle | What we do | What we avoid |
|---|---|---|
| Feedback early | Install Nix day 1; first NixOS host in week 2 | 3+ weeks of pure language before any OS |
| Modern defaults | Flakes + nix CLI as default; classic CLI as literacy |
Building muscle memory on nix-env / channels as primary |
| Host before packaging craft | Configure and consume packages on a real system first | Deep stdenv before you have felt closure size and rebuilds |
| System then user | NixOS host stable → Home Manager for the user layer | Dotfiles-only Nix that never owns the machine |
| Just-in-time depth | Module types catalog after you have written real modules | A full week of lib.types before services.openssh.enable |
| Patterns over product zoo | Proxy, secrets, one DB, CI, observability as patterns | Required chapters for every self-hosted app |
| Internals last | Evaluator, daemon, CA derivations after you can operate | Sandbox namespaces before you can roll back a bad config |
| Prove rebuildability | Capstone = wipe + rebuild from flake | “It worked once on my laptop” |
How the three sources were used
| Source | Role |
|---|---|
| 90 Days of X Session 2 | Day prompts, mini-projects, 26.05 notes, deploy/secrets tool names |
| 90 Days of X Zai | Depth checklists (language, store, module types, HM, troubleshooting) |
| PDF syllabus | Production stack, hardening, multi-node capstone bar |
Rejected as primary structure: Zai’s flakes-before-any-OS calendar; Zai’s 21-day language-only front load; older “Day 27–50 install every service” tables; PDF cert/RHCE framing.
Optional link to Go (Volume 1)
This volume does not require the Go volume. If you already write Go (or any language), Stage V is a natural place to package a real binary. Do not stall NixOS waiting for another language curriculum.
Modern stack (defaults for this book)
| Layer | Default choice |
|---|---|
| Pinning | Flakes + flake.lock |
| CLI | Modern nix (build, run, develop, flake, shell, profile) |
| System | NixOS modules + nixos-rebuild / nixos-rebuild --flake |
| User | Home Manager as NixOS module (standalone when on non-NixOS) |
| Disks | Disko when reinstalling or provisioning |
| Secrets | sops-nix (primary); agenix compared once |
| Deploy | deploy-rs (single/simple) then Colmena (fleet) |
| Images | nixos-generators |
| Cache | cache.nixos.org + Cachix or self-hosted Attic/Harmonia |
| Boot security | Lanzaboote / Secure Boot when hardware allows |
| Tests | nixosTest + flake checks |
Classic nix-* commands appear for reading older docs and mental models—not as the preferred daily driver.
Lab 0 (before Day 1)
| Lab | Theme | You can leave when… |
|---|---|---|
| 0 / 0A | Single-server journey lab (KVM, storage, VMs, containers) | Disposable nixlab (+ optional deploy-a) exist; wipe boundary clear |
| 0B | NixOS dev environment on host (or dedicated) | Flake repo, editor/LSP, SSH to guests, conservative max-jobs |
| 0C | Hardware profile (e.g. HP Elitebook 2570p · 16 GB) | BIOS VT-x, RAM split, disk plan documented |
| 0D | Ops cheatsheet | Snapshot / SSH / disk-full recovery known |
Chapters: 01a–01e under this volume (sidebar after Syllabus, before Day 1).
Lab 0 (before Day 1)
| Lab | Theme | You can leave when… |
|---|---|---|
| 0 / 0A | Single-server journey lab (KVM, storage, VMs, containers) | Disposable nixlab (+ optional deploy-a) exist; wipe boundary clear |
| 0B | NixOS dev environment on host (or dedicated) | Flake repo, editor/LSP, SSH to guests, conservative max-jobs |
| 0C | Hardware profile (e.g. HP Elitebook 2570p · 16 GB) | BIOS VT-x, RAM split, disk plan documented |
| 0D | Ops cheatsheet | Snapshot / SSH / disk-full recovery known |
Chapters: 01a–01e (sidebar after Syllabus, before Day 1).
Stage map
| Stage | Days | Theme | You can leave when… |
|---|---|---|---|
| I | 1–10 | Foundations: mindset, language-in-context, store, modern CLI, first flake shell | You build a pinned dev shell and explain a store path |
| II | 11–22 | One flake-based NixOS host | You rebuild, roll back, and own users/net/packages |
| III | 23–32 | Layout, Home Manager, multi-output flake discipline | System + user config live in one clean flake |
| IV | 33–44 | Secrets, hardening, service patterns, light containers | A small server slice is declarative and secret-safe |
| V | 45–56 | Packaging, overlays, caches, build debugging | You ship a package you use and push substitutes |
| VI | 57–70 | Disko, deploy, images, tests, CI | Lab deploys remotely and is tested in CI |
| VII | 71–82 | Internals, ecosystem, release currency | You can debug eval/store issues and plan 26.05→26.11 |
| VIII | 83–90 | Capstone | Wipe/rebuild proof (+ optional multi-node bar) |
Days are a pacing guide (~4h blocks when possible: ~25% concept / ~55% hands-on / ~20% review), not rigid calendar law.
Stage I — Foundations (Days 1–10)
Goal: Correct mental model + modern toolchain before owning a machine.
| Day | Focus | Expert emphasis | Hands-on |
|---|---|---|---|
| 1 | Why Nix exists | Dependency hell, snowflake servers, reproducibility limits (honest); Nix language vs package manager vs NixOS | Install Nix (multi-user); enable flakes + new CLI; first nix repl |
| 2 | Store & closures | Content addressing, store paths, GC roots at a glance | Inspect a package closure; find what keeps it alive |
| 3 | Language: values & attrsets | Types, let, nested sets, inherit — only what you need to read nixpkgs |
Model a small config as an attrset |
| 4 | Language: functions | { a, b ? d }:, @, ellipsis, composition |
Write helpers used later in a flake |
| 5 | Laziness, imports, lib taste |
Imports are eager, values lazy; lib as standard library |
Multi-file expression; one lib pipeline |
| 6 | Derivations as idea | Evaluation vs realization; .drv vs outputs; sandbox why |
nix build something tiny; read nix log |
| 7 | Modern CLI fluency | build / run / develop / shell / flake show |
Prefer modern CLI for all tasks this day |
| 8 | First flake (project) | inputs / outputs / lock; devShell before OS |
Flake with devShells.default for a real project |
| 9 | Classic CLI literacy | Map old → new (nix-build, nix-shell, channels as history) |
Same task once classic, once modern |
| 10 | Gate | Foundations review | Pin nixpkgs; recreate shell on a clean machine/VM user |
Depth from Zai (weave in, do not pre-schedule 21 days): conditionals/operators, with pitfalls, string interpolation, isAttrs/type checks, fixed-point awareness, FOD concept, sandbox/substitute vocabulary.
Exit criteria: Explain store path + lock file; nix develop works offline after first populate; no dependency on channels for your project.
Stage II — One flake-based NixOS host (Days 11–22)
Goal: Generations, rollback, and “the module system as a user” before authoring a framework.
Expert default: Install and manage the first host with flakes from day one of NixOS. Do not invest two weeks in a non-flake configuration.nix only to rewrite it.
| Day | Focus | Expert emphasis | Hands-on |
|---|---|---|---|
| 11 | Install | VM/spare disk; UEFI; Disko intro or manual once; generate hardware config | Bootable NixOS 26.05 lab |
| 12 | Flake host skeleton | nixosConfigurations; nixos-rebuild switch --flake .#host |
First flake-defined rebuild |
| 13 | Rebuild modes & generations | switch / test / boot / build; boot menu rollback | Deliberate break → roll back |
| 14 | Users & access | Declarative users; SSH keys only for remote; avoid plaintext password habits | Non-root admin pattern |
| 15 | Networking & firewall | networkd vs NM; open only what you need | Static or known DHCP + SSH |
| 16 | Packages & programs | environment.systemPackages vs programs.* modules |
Install daily tools declaratively |
| 17 | systemd via Nix | One custom service + timer | Module snippet that generates units |
| 18 | Modules as consumer | Read options + source for 2–3 nixpkgs modules; mkIf / mkDefault |
Change behavior via options, not forks |
| 19 | First custom module | options + config, imports, one assertion |
Extract something from configuration into a module |
| 20 | Boot & hardware | systemd-boot vs GRUB; kernel packages; firmware | Document your boot path |
| 21 | Filesystems intro | Mounts; state vs store; impermanence idea only | Label what must persist |
| 22 | Gate | Minimal production-shaped host | Users, SSH, firewall, one service, one custom module — all in flake |
Defer to later stages: full Disko redesign, multi-host, secrets machinery, deep type catalogs.
Exit criteria: From cold boot you can roll back; flake is the only source of truth for the lab host.
Stage III — Daily-driver shape (Days 23–32)
Goal: Structure that scales past one file; user environment without polluting system closure carelessly.
| Day | Focus | Expert emphasis | Hands-on |
|---|---|---|---|
| 23 | Flake layout | Split hosts/ / modules/ / homes/; avoid 2k-line flake.nix |
Refactor Stage II into layout |
| 24 | Lock discipline | Selective flake update; pin strategy; registries lightly |
Update one input only; explain lock diff |
| 25 | Home Manager on NixOS | HM as NixOS module first (one activation story) | User programs: shell, git, ssh |
| 26 | HM files & XDG | home.file, xdg.configFile; theming only if you care |
Migrate real dotfiles |
| 27 | HM services | User systemd timers/services | One user service you actually want |
| 28 | Dev shells + direnv | Project shells outside systemPackages | use flake on a repo |
| 29 | flake-parts (or discipline) | Reduce boilerplate or hand-roll cleanly — pick one style | Consistent multi-output flake |
| 30 | Checks | nix flake check; format/lint as checks |
Fail CI-shaped check locally |
| 31 | Overlays (light) | Pin or patch one package for the host | Overlay consumed by host + shell |
| 32 | Gate | Workstation/server skeleton | Host + HM + devShell + checks in one flake |
Zai HM depth (required coverage across 25–27): programs modules, file permissions/templating, XDG, multi-machine user splits as pattern.
Exit criteria: New machine of same role = clone flake + hardware config + rebuild.
Stage IV — Real services, secrets, isolation (Days 33–44)
Goal: Operate services like production without leaking secrets into the store.
| Day | Focus | Expert emphasis | Hands-on |
|---|---|---|---|
| 33 | Secret problem | Why strings in Nix are dangerous; store world-readable truth | Find a “secret” anti-pattern and remove it |
| 34 | sops-nix | Encrypted-in-repo, decrypt at activation | One secret end-to-end |
| 35 | agenix comparison | Age keys; trade-offs; pick a house default | Same secret second way once |
| 36 | Hardening baseline | SSH, sudo, unused services off, kernel defaults carefully | Apply a small hardening module |
| 37 | Firewall discipline | Per-service ports; deny by default | Audit open ports |
| 38 | TLS front door | ACME + Caddy or Nginx — one reverse-proxy pattern | HTTPS to a static or app backend |
| 39 | Data service pattern | PostgreSQL or other one DB — modules, state dirs, backups thought | Declarative DB + app user |
| 40 | nixos-containers / OCI | When containers help on NixOS; not “Docker first” | One declarative container or nspawn |
| 41 | Podman/Docker modules | Rootless notes; prefer OCI module over snowflake | Compare to Day 40 |
| 42 | Observability pattern | Prometheus + Grafana or minimal logs first | Metrics for one service |
| 43 | Optional: k3s lite | Only if you need k8s; single-node | Skip cleanly if not |
| 44 | Gate | Lab slice | Proxy + secret + one app/data path + firewall story |
Not required: Matrix, Nextcloud, Jitsi, full “homelab app of the day” lists. Revisit after capstone if you want.
Exit criteria: grep-able repo has no live secrets; slice rebuilds on a fresh VM from flake + keys.
Stage V — Packaging craft (Days 45–56)
Goal: Produce software, not only consume it—after you know how packages feel on a host.
| Day | Focus | Expert emphasis | Hands-on |
|---|---|---|---|
| 45 | stdenv phases | unpack→install→fixup; hooks; build vs native inputs | Package a small C/shell tool properly |
| 46 | Fetchers & FODs | Hash mismatch workflow; fetchFromGitHub |
Package from a tag |
| 47 | Language ecosystem A | Your primary language helper (buildGoModule, etc.) |
Package a tool you use |
| 48 | Language ecosystem B | Second ecosystem for pattern transfer | Smaller package |
| 49 | Patching & overrides | overrideAttrs, patches, overlays composition |
Fix or pin something broken |
| 50 | Multiple outputs | Closure size discipline | Split out/dev/doc |
| 51 | Debug builds | nix log, --keep-failed, breakpointHook |
Break and recover |
| 52 | nixpkgs layout | by-name, conventions, meta |
PR-shaped package (submit optional) |
| 53 | Binary caches | Push/pull; trust/signatures awareness | Private or Cachix push |
| 54 | Remote builders | Offload when useful | Second VM as builder |
| 55 | Reproducibility honesty | What is and is not bit-for-bit | Clean rebuild comparison |
| 56 | Gate | Package + cache | Flake output used by your host or CI |
Exit criteria: Someone else (or future you) builds your package from lock alone.
Stage VI — Fleet habits (Days 57–70)
Goal: Provision and deploy like infra, not like a pet SSH session.
| Day | Focus | Expert emphasis | Hands-on |
|---|---|---|---|
| 57 | Disko for real | Declarative disks on reinstall/cloud | Install/reinstall with Disko |
| 58 | Impermanence (optional commit) | Persist deliberately | Prove reboot drops unpersisted state or document why you skip |
| 59 | deploy-rs | Simple push deploy | Deploy lab to remote VM |
| 60 | Colmena | Tags, multi-host, parallel | Two hosts (one may be local) |
| 61 | Shared modules | Roles vs hosts; no copy-paste drift | roles/web.nix pattern |
| 62 | Images & generators | Cloud image / custom ISO | Boot generated image |
| 63 | Terraform boundary | TF provisions, Nix configures | Sketch only is enough |
| 64 | nixosTest | VM tests for your modules | Test proxy or hardened SSH module |
| 65 | More tests | Expand suite; flake checks in CI shape | 3 meaningful tests |
| 66 | CI pipeline | GHA/GitLab + Nix installer; cache write | PR build of flake |
| 67 | GC & store hygiene | Roots, retention, optimise | Policy + measured store size |
| 68 | Secure Boot / TPM path | Lanzaboote / LUKS unlock — hardware permitting | Document supported path or lab limits |
| 69 | Backup story | Borg/Restic/ZFS — pick one; declare it | Restore drill of state |
| 70 | Gate | Remote lab | Flake deploy + CI + cache + test green |
Exit criteria: New host of an existing role is boring.
Stage VII — Depth & currency (Days 71–82)
Goal: Debug and upgrade without superstition.
| Day | Focus | Expert emphasis | Hands-on |
|---|---|---|---|
| 71 | Evaluator | Thunks, infinite recursion patterns | Trace a tricky eval |
| 72 | Module system deep | Full type catalog (Zai list); mkMerge / priorities |
Redesign one module with proper types |
| 73 | Store & daemon | Substituters, signatures, sandbox namespaces | Explain roots + one sandbox log |
| 74 | Performance | --max-jobs / cores / eval cache |
Speed a full rebuild |
| 75 | CA derivations | Experimental awareness | Optional small experiment |
| 76 | nixosTest mastery | Flaky tests, networking in tests | Harden test suite |
| 77 | Ecosystem map | devenv, Snowfall, nix-darwin — try one, don’t collect all | Written comparison to your layout |
| 78 | Comparative landscape | Guix / image-based distros / Ansible — trade-offs | Short honest note |
| 79 | 26.05 release notes | Primary source, not blogs | Annotate impact on your flake |
| 80 | Upgrade planning | 26.05 → 26.11 dry-run | Written upgrade checklist |
| 81 | Troubleshooting drill | Boot, build, service, network matrix (Zai + PDF) | Fix injected failures |
| 82 | Architecture review | Map Stages I–VI onto design | Gap list before capstone |
Stage VIII — Capstone (Days 83–90)
Capstone A — required
Build (or finish) a flake-defined lab that includes:
- At least one NixOS host role you understand end-to-end
- Home Manager for your user (if workstation) or minimal service user story (if server-only)
- Secrets via sops-nix or agenix (house default)
- One reverse-proxy or equivalent edge pattern
- Deploy path (deploy-rs and/or Colmena)
- At least one
nixosTestor flake check that would catch a real regression
- CI that builds and preferably pushes a cache
| Day | Focus |
|---|---|
| 83–87 | Implement gaps; refactor modules; document architecture |
| 88 | Disaster recovery: wipe lab disk/VM; rebuild from flake + keys alone |
| 89 | Rollback drill + full test suite + troubleshooting checklist |
| 90 | Retrospective: what you would teach a friend in 1 day; roadmap (26.11, nixpkgs PR, Capstone B) |
Capstone B — stretch (PDF bar)
Only after A:
- ≥3 nodes, Colmena + Disko
- LUKS (+ TPM if available)
- Secure Boot / Lanzaboote if feasible
- Fleet observability
- CI → cache → deploy automation
Weekly review habit (from Zai, kept)
Every ~7 study days:
- Refactor modules (DRY, naming, options)
- Re-read one official manual page you used
- Write 5 “gotchas” in your own words
- Delete or quarantine experiments that taught something but should not ship
Completeness audit (sources → stages)
| Theme | Stage(s) |
|---|---|
| Philosophy, store, GC, sandbox | I, VII |
| Language depth | I (JIT), VII types revisit |
| Modern + classic CLI | I |
| Flakes, locks, checks | I, III |
| First host, rebuild, boot, net, users | II |
| Module system practice → deep types | II, VII |
| Home Manager depth | III |
| Dev shells, direnv | I, III |
| Secrets, hardening, proxy, DB pattern | IV |
| Containers / optional k3s | IV |
| Packaging, overlays, caches | V |
| Disko, deploy, images, CI, tests | VI |
| Secure Boot / TPM / Lanzaboote | VI–VIII |
| Internals, upgrades, ecosystem | VII |
| Capstone rebuild proof | VIII |
| App product zoo | Out (optional post-book) |
| Cert tracks | Out |
Explicitly out of scope
- Go curriculum (separate volume; not a dependency)
- Certification branding or exam prep
- Exhaustive self-hosted app catalog as required chapters
- Replacing nixos.org / nix.dev
Resources (primary, not blogs-of-2022)
- Nix Pills — store/derivation intuition (Stage I)
- nix.dev — maintained tutorials (I–III)
- Official NixOS & Nix manuals + 26.05 release notes
- NixOS & Flakes Book (community) — companion for flake layouts
- Upstream READMEs: sops-nix, agenix, Disko, deploy-rs, Colmena, Lanzaboote
Writing rule for future chapters
- Follow Stages I→VIII in order.
- Each chapter: mental model → minimal working flake/config → break it → gotchas.
- Prefer the default stack table unless hardware forces a fork (document the fork).
- After content moves:
bash scripts/update-index.shonly — never hand-edit_quarto.yml.
- Syllabus changes first if scope changes.