A declarative macOS workspace. Nix Flakes + nix-darwin + home-manager. Apple Silicon. Terminal-first. Opinionated. Zero bloat.
Built for me. Tried not to bloat it; only stuff I actually use daily. Clone it, rip out what you don't need, make it yours.
One darwin-rebuild switch and the machine is mine β Finder tamed, dock stripped, touch-ID-for-sudo on, apps installed, dotfiles symlinked, shell loaded. Wipe the Mac, run the command, come back to an identical machine.
Why Nix over brew install lists and stow symlinks:
- Reproducible. Same flake + same commit = same system. No drift. Roll back with
darwin-rebuild --rollback. - Atomic. A switch either fully applies or doesn't. No half-installed state when the network dies.
- Layered.
darwin.nixowns the system,home.nixowns the user,config/owns program configs. Nothing lives only in a GUI preference pane.
Only for Apple Silicon. Tested on a fresh M1 MacBook Air. Read it through once before pasting.
These strings are mine, not yours. Change them or the rebuild fails:
| File | What | Change to |
|---|---|---|
flake.nix |
darwinConfigurations."anuj-macbook" |
your hostname |
flake.nix |
username = "anujpokhriyal" |
your short username |
modules/git.nix |
programs.git.settings.user (Name/Email/Signing Key) |
your git identity |
Check your current hostname:
scutil --get LocalHostNameEither rename the machine (sudo scutil --set LocalHostName "your-host") or edit flake.nix β your call. Also review darwin.nix for the casks list, dock.persistent-apps, and the loginwindow.LoginwindowText ("Stay Away") β make them yours or remove them. Same for the configs in config/.
xcode-select --installcurl --proto '=https' --tlsv1.2 -L https://nixos.org/nix/install | shRestart your terminal, then verify:
nix --versiongit clone https://github.com/anujj14/dotfiles.git ~/nix-darwin
cd ~/nix-darwinnix --extra-experimental-features "nix-command flakes" run nix-darwin -- switch --flake .#anuj-macbook(replace anuj-macbook with the hostname from step 0)
First run is slow β it's compiling/downloading your whole system. Subsequent runs are seconds. After it finishes:
exec zshβ¦and restart the Mac once so the system-level defaults (dock, finder, loginwindow) pick up cleanly.
If macOS prompts about
iinaor any app from an unidentified developer, approve it in System Settings β Privacy & Security. One-time thing.
β οΈ Note on Existing Configs: If you already have existing dotfiles (like~/.config/aerospace), this flake will not delete them. Home Manager will safely back them up by appending.bakto the folder name before linking the new configs.π± Note on Immich (Dock Icon): The dock configuration expects Immich to be installed as a Safari Web App. After your first switch, open Safari, navigate to your Immich instance, and click
File > Add to Dock. If you don't use Immich, remove its path fromdarwin.nixbefore building or just remove dock icon later.
I use the NightTab extension. If you like it you can grab my layout file here: nighttab-batman.json.
Just import it via Settings -> Data -> Restore -> Import from file.
cd ~/nix-darwin
sudo darwin-rebuild switch --flake .#anuj-macbookIdempotent β Nix computes the diff and only touches what changed.
nix flake update --flake .
darwin-rebuild switch --flake .#anuj-macbook
git add flake.lock && git commit -m "chore: bump flake inputs"flake.lock is the reproducibility contract β always commit it. Do this every week or two to pull fresh nixpkgs-unstable.
darwin-rebuild --rollback
# or pick a specific generation:
darwin-rebuild --list-generations
darwin-rebuild switch --generation <N>nix-collect-garbage --delete-older-than 14d| Task | Command |
|---|---|
| Apply changes | darwin-rebuild switch --flake .#anuj-macbook |
| Update all inputs | nix flake update --flake . |
| Rollback | darwin-rebuild --rollback |
| List generations | darwin-rebuild --list-generations |
| Garbage collect | nix-collect-garbage --delete-older-than 14d |
| Inspect flake | nix flake show |
The whole point of not bloating the main desktop. Drop a `flake.nix` in any project:
{
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
outputs = { nixpkgs, ... }: let
system = "aarch64-darwin";
pkgs = nixpkgs.legacyPackages.${system};
in {
devShells.${system}.default = pkgs.mkShell {
packages = with pkgs; [ python311 k3d opentofu kubectl helm ];
};
};
}nix develop # enter the env
exit # leave it β nothing installed globally, nothing to uninstallIsolated packages for just one project? Python, brew, and pip drama β you know it I know it. Nix fixes the whole mess.
Don't even want a project flake for a single command? nix shell drops you into
a shell with a package available, then forgets about it the moment you leave:
nix shell nixpkgs#ffmpeg
ffmpeg -i input.mp4 output.gif
exit # ffmpeg is gone from PATH, nothing was "installed"Or skip the subshell entirely and run it as one line:
nix shell nixpkgs#ffmpeg -c ffmpeg -i input.mp4 output.gifNo brew install ffmpeg you'll forget about six months later, no version
conflicts with some other tool that also wants ffmpeg. The package is pulled
from the Nix store and cached β so the next nix shell nixpkgs#ffmpeg is
instant β but it never touches your PATH outside that shell or this flake.
Run nix-collect-garbage --delete-older-than 14d occasionally to reclaim disk
space from packages you've stopped using.
nix-homebrewfor declarative casks/taps. Rosetta off. Auto-migrate from legacy brew.- Touch ID for
sudo(security.pam.services.sudo_local.touchIdAuth). - Finder: list view, pathbar + statusbar, all extensions + hidden files visible, desktop icons killed, search scoped to current folder, new windows open at
$HOME. - Key repeat cranked (
InitialKeyRepeat 15,KeyRepeat 2), press-and-hold disabled, trackpad scaling 2.0, tap-to-click, three-finger drag. No auto-capitalization, no spell-correct. - Dock: autohide, tile 57, magnify to 67,
scaleminimize, minimize-to-application, recents off. - Screenshots β
~/Pictures/Screenshotsas.jpg. Siri off, Time Machine nagging off, no.DS_Storeon network/USB volumes. - Loginwindow text: "Stay Away".
| App | Why it's here |
|---|---|
| Ghostty | Default look is so good I barely configure it. |
| AeroSpace | Tiling WM in native Swift. No SIP disable like yabai |
| JankyBorders | Via native darwin.nix. Borders for active and inactive windows. |
| Zed | Opens instantly, real vim bindings, written in Rust. I live in nvim; Zed is for when I actually need to code. |
| Zen | Arc browser that still gets updates. Firefox-based. f chrome. |
| Helium | Ungoogled, de-bloated Chromium for the few times Chromium is unavoidable. Sips RAM. |
| OrbStack | The Docker Desktop replacement on Apple Silicon. Sips CPU/RAM. Podman on macOS isn't there yet. |
| Tailscale | Mac as exit-node for my phones, reaching the homelab from anywhere. |
| IINA | Best video player on macOS. |
| LocalSend | Open-source AirDrop. |
| Shottr | Miles better than default screenshots. Quick copy, edit, done. |
| Signal / WhatsApp / Telegram | Privacy + have to use what people use :( |
| AppCleaner | Because macOS still doesn't know how to uninstall an app. |
| Impactor | IPA sideloader for iPhone/iPad. FU to Apple for not letting me install what I want on devices I own. |
| Iris | Quick webcam check(HandMirror alt). |
| Ice | macOS menu bar customizations. Sketchybar is way more pretty but can't match default for utility. |
CLI packages (from nixpkgs-unstable):
| Tool | Why |
|---|---|
| neovim | The best editor. I keep it mostly default β no heavy modding. Configured using modules. |
| tmux | Terminal multiplexer. You know what it does. |
| starship | So I don't have to configure oh-my-zsh and its bloat. Starship defaults are already the best. |
| zoxide | cd with memory. z proj jumps to ~/code/projects after one visit. |
| fzf | For the searches macOS Spotlight can't do. --height 40% --border. |
| btop | Activity Monitor is painfully slow. btop is faster β though it's inaccurate sometimes. |
| yazi | File explorer in the terminal. For when I don't want to leave the shell. |
| fastfetch | Updated neofetch. For those cool screenshots. |
| tree | Visual ls for viewing file/directory structure. |
| pass | Unix password manager. (not fully migrated yet, but trying). |
| android-tools | adb into my Android TV and phones. |
| cmatrix | The Matrix screensaver. Pure flex for the screenshot. |
Shell: Zsh β macOS default. home-manager manages: autosuggestions, syntax highlighting, completion. Starship prompt. Zoxide for z. fzf integrated with zsh.
- nix-darwin β declarative macOS.
- nix-community/home-manager β declarative home.
- zhaofengli/nix-homebrew β declarative Homebrew.
- nikitabobko/AeroSpace β for making this awesome window manager for macOS.
- FelixKratz/JankyBorders β He does a lot of macOS ricing work. Creator of Sketchybar & JankyBorders. Check him out.
- Everyone shipping the open-source apps above.
Built for me. Shared so you can build for you.


