My personal MacBook had a disagreement with a little bit of water. Got drowned. Basically all data lost.
When it came back from repair, I cloned the repo and ran one command: nix run .#build-switch. About ninety minutes later, the Dock looked right, zsh was configured, Homebrew was installed with all the casks, and my terminal opened with the correct font.
I have never not appreciated that.
The setup is one Nix flake managing three machines: personal MacBook, work MacBook, NixOS desktop. They share a 70+ package core — same shell, same tools, same muscle memory everywhere. The 10% that differs (work casks, personal side projects, different Dock layouts) lives in per-host config.
A few things that were more interesting to build than I expected:
- Declarative Dock management — an activation script that diffs the current layout against a declared list, removes extras, adds missing entries. Fresh machine: correct Dock, automatically.
- launchd automation with guard files — one-time agents that run once, write a sentinel file, then skip on every subsequent rebuild. Colima starts at login. Spotlight loses Cmd+Space to Raycast. All in config.
-
Brave profile launchers — generated shell scripts (
brave-personal,brave-work) that appear in PATH automatically.
The part I found hardest to explain to people: this isn't a shell script that installs things. It's a description of desired state. Remove a package from the config and rebuild — it's gone. The system converges to what the config says, not what happened to accumulate over years.
The full post covers the four-layer architecture, the shared/per-host split in detail, how agenix + YubiKey handle secrets, and the real trade-offs (first setup is ~90 minutes; the Nix language will confuse you; "reproducible" has limits macOS permissions won't let you cross).
Read the full post on bullo.sk →
Config repo: github.com/dominikbullo/nix-config




















