· Administer NixOS/Nix: flakes, home-manager, nix-darwin, generations, overlays, disko. Triggers: 'nixos', 'nix', 'flake', 'home-manager', 'configuration.nix', 'nixos-rebuild'. Not for other distros.
Administer NixOS without falling back into imperative distro muscle memory. NixOS is
declarative, functional, and atomic: the system is a value computed from a configuration,
every change becomes a new immutable generation in
/nix/store
, and rollbacks are a
bootloader entry away. This skill keeps that model intact, then layers in the practical
stack: channels vs flakes,
nixos-rebuild
vs
nix
CLI, home-manager, nix-darwin, store
hygiene, overlays, module writing, secrets, and the Determinate Nix and Lix lanes.
The places NixOS breaks are NixOS-shaped: channel drift, flake input staleness, garbage
collection that nukes a needed derivation, overlays fighting,
nix-env -i
poisoning the
user profile, hardware modules missing, or people treating
/etc/nixos/configuration.nix
like a normal Linux config file.
Why people run it. Atomic upgrades and rollbacks, bit-for-bit reproducible systems,
disposable dev shells, fleet-wide configuration without a separate config-management tool,
and a single language for a workstation, a server, a container image, a NixOS VM, and a
macOS laptop via nix-darwin.
Versions worth pinning (verified April 2026):
Pin versions only when they shape compatibility or troubleshooting. For ordinary package
work, trust the live channel or flake lock over a stale table.
Lix lane: fork-specific behavior, coexistence, and migration notes
Integration with Docker, Kubernetes, and CI:
nix build
, image outputs, cachix, attic
When NOT to use
Arch or CachyOS administration - use arch-btw
Debian, Ubuntu, Mint, or Pop!_OS administration - use debian-ubuntu
Fedora, RHEL, CentOS Stream, Rocky, or Alma administration - use rhel-fedora
Kali Linux and offensive-tool distros - use kali-linux
Shell syntax, quoting, or portability outside Nix expressions - use command-prompt
Docker, Podman, image builds, or container runtime issues - use docker
Kubernetes cluster or manifest work - use kubernetes
Fleet-wide non-Nix Linux configuration via playbooks - use ansible
Terraform or OpenTofu infrastructure code - use terraform
Offensive or privesc testing - use lockpick
Defensive hardening and vuln review - use security-audit
OPNsense or pfSense appliance work - use firewall-appliance
AI Self-Check
Before returning NixOS or Nix commands, verify:
Lane identified: NixOS install, Nix on non-NixOS Linux, Nix on macOS (nix-darwin or plain Nix), WSL, Determinate Nix, or Lix. Advice diverges fast.
Channels vs flakes decided: confirm which the user has before prescribing
nix-channel
,
nixos-rebuild --flake
, or
nix flake update
. Mixing without intent creates channel-lock drift.
Flake status is current: flakes remain nominally experimental on upstream Nix but are enabled by default on Determinate Nix; recommend enabling
experimental-features = nix-command flakes
where the user is already using flakes.
nix-env -i
is not the answer: installing into the per-user profile hides state from
configuration.nix
and breaks reproducibility. Use declarative
environment.systemPackages
,
home.packages
, or an ad-hoc
nix shell
instead.
No partial upgrade advice: on flakes-based systems, do not bump a single input without running
nixos-rebuild --flake
after; on channels, do not change only
nixos
without updating dependent channels too.
Rebuild verb is intentional:
switch
,
test
,
boot
,
dry-activate
,
build-vm
, and
build
differ.
test
does not persist the boot entry;
boot
does not activate now;
switch
does both.
Known-good generation preserved: never remove the last known-good generation, and never
nix-collect-garbage -d
on a system that just booted a new generation without verifying the new one survives a reboot.
GC roots respected: dev shells, direnv caches, and CI artifacts often hold GC roots. Do not recommend aggressive GC without checking
nix-store --gc --print-roots
first.
Unfree / insecure gates named explicitly: set
nixpkgs.config.allowUnfree = true;
or
allowUnfreePredicate
, and list insecure packages under
permittedInsecurePackages
. Do not default to
NIXPKGS_ALLOW_UNFREE=1
as the permanent answer.
Hardware module present: for fresh installs,
hardware-configuration.nix
must be regenerated with
nixos-generate-config
and not hand-edited for filesystem UUIDs. For laptops, check nixos-hardware profile.
Kernel and initrd coherence:
boot.kernelPackages
, initrd modules, filesystems, and bootloader agree. Do not casually swap kernels on a system with ZFS, NVIDIA, or custom out-of-tree modules.
Module fields real: options named in advice exist in the version of nixpkgs the user has.
options
graveyards drift between 23.11, 24.05, 24.11, 25.05, and 25.11 - verify against the
nixpkgs
tag the user pinned.
Secrets not put in the store: anything under
./secret.age
,
./sops.yaml
, or similar must be decrypted at activation time by sops-nix or agenix, not embedded directly in a Nix string that ends up world-readable in
/nix/store
.
disko / impermanence claims match the install: declarative disk layouts change the recovery story. Confirm partition, filesystem, and subvolume layout before prescribing rollback or wipe steps.
home-manager mode identified: standalone, NixOS module, or nix-darwin module.
home-manager switch
vs
nixos-rebuild switch
vs
darwin-rebuild switch
is not interchangeable.
Overlay placement sane: overlays belong in
nixpkgs.overlays
(NixOS) or as a flake input overlay. Do not recommend global
~/.config/nixpkgs/overlays.nix
on a flakes system where that path is often ignored.
Determinate / Lix advice scoped: Determinate's
determinate-nixd
and Lix's CLI diverge from upstream in subtle places. Name the lane before suggesting daemon or CLI flags.
Diagnostic errors are not silenced: do not hide useful output with
2>/dev/null
when the error text is the evidence. Use
2>&1 || true
when gathering.
Version pins justified: if a pinned
system.stateVersion
is suggested, explain why; do not change
stateVersion
on an existing system casually - it controls migration semantics.
Workflow
Step 1: Identify the Nix lane first
Lane
Default stance
What changes
NixOS installed (stable 25.11)
configuration.nix or flake.nix drives everything
full system is Nix-managed; rollbacks via bootloader
NixOS unstable / 26.05 pre-release
treat as rolling-ish
expect breakage; verify options still exist
Nix on non-NixOS Linux
user-level only
host distro still owns services and boot; no
nixos-rebuild
nix-darwin on macOS
declarative macOS config
darwin-rebuild switch
; host owns kernel and firmware
Plain Nix on macOS (no darwin)
package manager only
nix profile
or
nix shell
for user tooling
WSL2 with NixOS
full NixOS in WSL
boot and init differ; host owns kernel
Determinate Nix
flakes on by default, daemon differs
determinate-nixd
, parallel eval, lazy trees
Lix
upstream-compatible fork
CLI mostly matches; internals, error messages, and Meson build diverge
Step 2: Gather current system state
Start narrow. Widen only when the failing layer is still unclear.
Baseline checks for every NixOS or Nix case:
bash
# Identify OS and Nix lanecat /etc/os-release 2>&1||truenix --versioncommand-v nixos-version >/dev/null 2>&1&& nixos-version
command-v darwin-version >/dev/null 2>&1&& darwin-version
command-v determinate-nixd >/dev/null 2>&1&& determinate-nixd status
uname-a# Nix config and featuresnix config show 2>&1|grep-E'experimental-features|extra-experimental|substituters|trusted-users'||truecat /etc/nix/nix.conf 2>&1||true# NixOS-specific[[-d /etc/nixos ]]&&ls /etc/nixos
[[-f /etc/nixos/flake.nix ]]&&echo"flakes system"||echo"channels system (or flake elsewhere)"command-v nix-channel >/dev/null 2>&1&& nix-channel --list2>&1||truecommand-v nixos-rebuild >/dev/null 2>&1&& nixos-rebuild --help2>&1|head-5# Generations and bootcommand-v nix-env >/dev/null 2>&1&& nix-env --list-generations -p /nix/var/nix/profiles/system 2>&1|tail-5||true[[-d /boot/loader/entries ]]&&ls /boot/loader/entries 2>&1|tail-10command-v bootctl >/dev/null 2>&1&& bootctl status 2>&1|head-20||true# Store health and GC statedf-h /nix/store
du-sh /nix/store 2>&1||truenix-store --gc --print-roots 2>&1|wc-l
Add subsystem probes only when the task needs them:
When a problem looks "flake-only," compare one clean baseline:
delete
flake.lock
and re-lock, or
roll one input back to its previous rev via
nix flake lock --override-input
, or
build the same output on another machine with the same
flake.lock
to isolate hardware vs config.
Default Decisions
Declarative first.
nix-env -i
,
nix profile install
, and one-off
nixpkgs.config
tweaks are escape hatches, not workflows. If it survives across rebuilds, it belongs in the config.
Flakes when the user already has them. Do not migrate users off channels mid-troubleshoot. Do not migrate users onto flakes without naming tradeoffs (still experimental upstream, lockfile commits become a habit, registry overrides differ).
Generations are the rollback. Before debugging, confirm the previous generation boots. That is cheaper than chasing ghosts.
Store hygiene is boring and scheduled. Enable
nix.gc.automatic
and
nix.settings.auto-optimise-store = true;
rather than manual sweeps.
home-manager has three modes. Standalone, NixOS module, nix-darwin module. Pick one per host and stay there.
nix-darwin is opinionated. macOS system settings, LaunchDaemons, and Homebrew coexistence are what it owns. Do not treat it like NixOS with a different kernel.
Disko and impermanence are declarative recovery. They shine on fresh installs and nixos-anywhere deploys; retrofitting them onto a live system is a different, harder problem.
Secrets never go in the store. Use sops-nix or agenix with activation-time decryption.
Pick Determinate or Lix intentionally. Both are fine; both add behavior that diverges from upstream Nix in small but real ways. Name the lane.
Kernel changes are cross-layer. ZFS, NVIDIA, hardened kernel, and custom initrd modules all interact. Do not swap
boot.kernelPackages
casually.
Quick Triage Checklist
Symptom
First checks
nixos-rebuild
evaluation error
--show-trace
, check option name against the current nixpkgs tag, check
imports
paths
Build fails mid-derivation
--print-build-logs
, check sandbox violations, check unfree or insecure gates
Boot drops to emergency shell
previous generation from bootloader menu, check
hardware-configuration.nix
, LUKS, kernel modules
Flake input won't update
nix flake lock --update-input <name>
, check
inputs.<x>.follows
, check registry override
System is huge,
/nix/store
fills disk
nix-collect-garbage -d
,
nix-store --optimise
, prune generations, check direnv GC roots
nix-env -i
installed something that won't stick
user profile vs system config; move to
environment.systemPackages
or
home.packages
home-manager drift vs NixOS
standalone vs module mode, which one owns the file,
home-manager switch
vs
nixos-rebuild switch
Unfree package refuses to build
nixpkgs.config.allowUnfree = true;
or predicate, or
NIXPKGS_ALLOW_UNFREE=1 nix-build --impure
for one-off
Secrets in a module show up world-readable
moved to sops-nix/agenix and re-deploy; rotate the exposed secrets
ZFS or NVIDIA breaks after kernel bump
boot.kernelPackages = pkgs.linuxPackages_<pin>;
or wait for out-of-tree module to rebuild
nix-darwin change did not apply
darwin-rebuild switch
, not
nixos-rebuild
; check
users.users.<name>.home
and
nix.enable
Nothing makes sense
check gotchas reference - channel vs flake mixing, stale lock, overlay collisions, GC of an active dev shell
Reference Files
references/configuration-and-modules.md
-
/etc/nixos/configuration.nix
, modules, options, assertions,
mkMerge
and
mkForce
, NixOS module system
references/flakes-and-channels.md
- flakes,
flake.nix
anatomy, inputs and outputs,
flake.lock
,
nix flake
verbs, channels vs flakes vs npins
references/rebuild-generations-and-rollback.md
-
nixos-rebuild
verbs, generations,
nix-env --list-generations
, bootloader entries, rollback flow
references/home-manager-and-darwin.md
- home-manager (standalone, NixOS module, nix-darwin module), nix-darwin system configuration on macOS
references/overlays-packaging-and-overrides.md
- overlays,
overrideAttrs
,
override
,
callPackage
, writing derivations, patching upstream
references/store-gc-and-builders.md
- Nix store,
nix-store
vs
nix store
, GC roots,
nix-collect-garbage
, optimise-store, remote builders, Cachix and attic
references/dev-shells-and-direnv.md
-
nix-shell
,
nix develop
,
shell.nix
,
default.nix
, flake dev shells,
nix-direnv
, per-project env
references/disko-impermanence-and-imaging.md
- disko partitioning, impermanence, nixos-anywhere, SD/ISO images with nixos-generators
- recurring NixOS and Nix failure patterns and edge cases
Related Skills
arch-btw - Arch and CachyOS administration. Use it when the host is Arch-family and Nix is a side tool, not the system.
debian-ubuntu - Debian-family administration. Use it when Nix runs on Debian/Ubuntu as a user-level package manager only.
rhel-fedora - RHEL-family administration. Use it when Nix runs on Fedora/RHEL as a user-level package manager only.
kali-linux - Kali distro workflow. Use it for Kali, not for Nix inside Kali.
command-prompt - shell syntax, aliases, and one-liners outside Nix expressions.
docker - container runtime and image concerns. This skill builds images with
dockerTools
; docker runs them.
kubernetes - cluster workloads once the build output leaves Nix.
ansible - fleet config management when Nix is not the chosen tool for the job.
terraform - IaC for cloud resources that host NixOS VMs; this skill owns the guest.
security-audit - defensive review of a Nix-built artifact.
update-docs - sync docs after substantial module or flake restructuring.
Rules
Identify the Nix lane before prescribing commands. NixOS vs Nix-on-host, channels vs flakes, Determinate vs upstream vs Lix, standalone vs module home-manager - all change the answer.
Declarative beats imperative. If the fix is
nix-env -i
, reach for
environment.systemPackages
,
home.packages
, or
nix shell
instead. Hidden profile state is a footgun.
Know the rebuild verb.
switch
,
test
,
boot
,
dry-activate
,
build-vm
, and
build
are not interchangeable.
test
does not persist across reboot;
boot
does not activate now.
Preserve a known-good generation. Never GC aggressively right after a rebuild. Boot the new generation twice before pruning.
Flakes are intentional. Enable
nix-command flakes
where the user already uses them; do not push migration during troubleshooting.
GC roots are real state. Dev shells, direnv caches, and CI pins hold them. Check before mass deletion.
Secrets never in the store. Use sops-nix or agenix with activation-time decryption; anything else ends up world-readable in
/nix/store
.
Module options must exist in the user's nixpkgs tag. 23.11/24.05/24.11/25.05/25.11 drift is real; confirm with
nix repl
or the options search before recommending.
Overlays compose, not mutate.
final: prev: { ... }
scope. Do not recommend global profile-level overlays on flake systems.
Kernel and initrd agree. Do not flip
boot.kernelPackages
on ZFS, NVIDIA, or custom-module systems without a fallback.
Do not touch
system.stateVersion
casually. It controls migration semantics and is not a "version bump" field.
Disko and impermanence are install-time decisions. Retrofit is a different, harder conversation.
home-manager mode is sticky. Pick standalone, NixOS module, or darwin module per host and stay there.
Determinate and Lix diverge at the edges. Name the lane before suggesting daemon or CLI flags.
Reach for common Nix failure patterns before exotic explanations. Channel/flake mixing, stale lock, overlay collision, option drift, GC of an active dev shell, and unfree/insecure gates explain a large share of the chaos.