NixOS / HomeManager Config
  • Nix 93.2%
  • Shell 6.8%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-07-30 17:14:10 +02:00
assets Add preview for darwin 2026-07-22 17:01:01 +02:00
home Update and remove claude 2026-07-30 17:14:10 +02:00
hosts Add Plymouth 2026-07-26 15:11:45 +02:00
.gitignore switch to dms 2026-07-19 01:25:30 +02:00
deploy.sh Fully add txl macos config 2026-07-22 15:15:51 +02:00
flake.lock Update and remove claude 2026-07-30 17:14:10 +02:00
flake.nix Update README and switch to zen on txl 2026-07-22 15:49:12 +02:00
install.sh Add disko for rxl and auto install 2026-07-22 00:03:26 +02:00
README.md Add preview for darwin 2026-07-22 17:01:01 +02:00

nix

Flake configuration for NixOS hosts (pxl, rxl) and a nix-darwin host (txl). Linux stack: niri WM · DankMaterialShell (DMS) + native dms-greeter · kitty + fish. macOS stack: aerospace WM · kitty + fish · nix packages for everything CLI, homebrew for GUI casks only.

preview preview-darwin

Structure

nix/
├── flake.nix                  # inputs + nixosConfigurations (pxl, rxl) + darwinConfigurations (txl)
├── deploy.sh                  # deploy script, branches on uname
├── assets/
│   └── wp.jpg                 # wallpaper (Linux only)
├── home/                      # home-manager
│   ├── default.nix            # entry point — imports common/ + linux/ or darwin/ by platform
│   ├── common/                 # applied on every host, Linux and macOS alike
│   │   ├── packages.nix        # cross-platform CLI tools
│   │   ├── shell.nix           # fish + aliases (rebuild alias branches on platform too)
│   │   ├── terminal.nix        # kitty
│   │   ├── neovim.nix
│   │   ├── git.nix
│   │   └── zed.nix
│   ├── linux/                  # Linux/Wayland only
│   │   ├── packages.nix        # GUI apps, GTK, cursor, session vars
│   │   ├── dms.nix             # bar, launcher, wallpaper, theme
│   │   ├── niri.nix            # keybinds, layout, window rules
│   │   ├── dank-calendar.nix
│   │   ├── zen-browser.nix
│   │   ├── pdf.nix
│   │   └── xdg.nix
│   └── darwin/                 # macOS only
│       ├── aerospace.nix       # aerospace package + ~/.aerospace.toml
│       ├── aerospace.toml
│       └── apps.nix            # links Nix-built .app bundles into ~/Applications
└── hosts/
    ├── common/
    │   └── default.nix        # shared NixOS system config (audio, fonts, portal, greeter, …)
    ├── pxl/                   # desktop — Secure Boot, dual-boot Windows
    │   ├── default.nix
    │   └── hardware-configuration.nix
    ├── rxl/                   # laptop — standard boot, no dual-boot
    │   ├── default.nix
    │   └── hardware-configuration.nix
    └── txl/                   # MacBook — nix-darwin, homebrew for the rest
        └── default.nix

Every NixOS host gets hosts/common/default.nix (system) plus home/common + home/linux (user config). txl gets hosts/txl/default.nix plus home/common + home/darwin — there's no hosts/common equivalent shared across OSes, since NixOS and nix-darwin system options don't overlap much beyond home/common.

Host differences

pxl rxl txl
OS NixOS NixOS macOS (nix-darwin)
Bootloader lanzaboote (Secure Boot) systemd-boot
Dual boot Windows (nvme1n1p1)
WM niri niri aerospace
Extra packages sbctl homebrew casks/formulae (hosts/txl/default.nix)

Deploy

# on the target machine, from ~/nix:
sudo bash deploy.sh         # NixOS hosts (pxl, rxl) — uses $(hostname) to pick the config
sudo bash deploy.sh         # txl (macOS) too — darwin-rebuild requires sudo as of current nix-darwin
sudo bash deploy.sh txl     # explicit host works the same way on either OS

The script picks nixos-rebuild or darwin-rebuild based on uname, and runs directly against this repo — no copying to /etc/nixos. Each NixOS host's hardware-configuration.nix lives in hosts/<host>/ and is tracked in git like everything else, so the flake source is the single source of truth. The nrs/nrb fish aliases (home/common/shell.nix) do the same thing directly, without going through deploy.sh, and pick the right rebuild command for the current platform too.

Adding a new host

NixOS:

  1. Create hosts/<name>/default.nix importing ../common/default.nix — put only boot/hardware specifics here
  2. Copy that machine's /etc/nixos/hardware-configuration.nix to hosts/<name>/hardware-configuration.nix
  3. Add a nixosConfigurations.<name> entry in flake.nix, including hmConfigLinux in its module list
  4. On the new machine: install NixOS, clone this repo, run sudo bash deploy.sh <name>

macOS: create the user account via Setup Assistant first (see "macOS setup" below), install Nix + nix-darwin, add a hosts/<name>/default.nix, add a darwinConfigurations.<name> entry in flake.nix passing system = "aarch64-darwin" (or x86_64-darwin) directly to darwinSystem with hmConfigDarwin, then sudo bash deploy.sh <name>.

Either way, the new host inherits home/common automatically, plus home/linux or home/darwin — no per-host home-manager setup needed.

Secure Boot (pxl)

Keys are managed by sbctl at /var/lib/sbctl. After a fresh install:

sudo sbctl create-keys
sudo sbctl enroll-keys --microsoft   # from UEFI Setup Mode

macOS setup (txl)

Prerequisite: unlike NixOS, nix-darwin doesn't create the macOS user account — go through the normal macOS Setup Assistant first and make sure the account name matches users.users.tobias in hosts/txl/default.nix (here, tobias). nix-darwin only configures that already-existing account (home, shell, groups); it can't materialize one from nothing the way a NixOS install does.

First-time bootstrap, once that account exists:

# 1. Install Nix (Determinate installer — flakes enabled by default)
curl -fsSL https://install.determinate.systems/nix | sh -s -- install

# 2. Clone this repo
git clone git@github.com:tobikli/nix.git ~/nix

# 3. Bootstrap nix-darwin and switch — needs sudo (system activation must run as root)
cd ~/nix
sudo nix run nix-darwin -- switch --flake .#txl

# after that, use deploy.sh / the nrs fish alias like any other host

Homebrew itself is not pre-installed — nix-darwin's homebrew module (hosts/txl/default.nix) installs and manages it. It's cask-only by design: every CLI tool is a nix package (home/common/packages.nix for cross-platform ones, home/darwin/packages.nix for macOS-only ones like terraform/kubectl/azure-cli), and homebrew only carries GUI apps that don't have a good nix equivalent (IntelliJ, Obsidian, OrbStack, …) — browsers included, since Zen Browser (home/common/zen-browser.nix) is fully nix-managed on both OSes. onActivation.cleanup = "uninstall" means any cask not listed gets removed on the next switch — if migrating an existing Mac, run brew list first and add anything worth keeping to the casks list before that first switch, or it gets uninstalled immediately.

Gotchas hit building this (worth knowing before touching hosts/txl or adding another darwin host)

  • system must be passed directly to darwinSystem in flake.nix (not via nixpkgs.hostPlatform in the host module) — combining the latter with home-manager.useGlobalPkgs causes infinite recursion during eval.
  • home/default.nix's imports must not branch on pkgs (e.g. pkgs.stdenv.isDarwin) — under useGlobalPkgs, pkgs is threaded through config._module.args, and imports resolves before config exists, so referencing it there recurses too. Use the isDarwin extraSpecialArgs (set per-OS in flake.nix) instead.
  • Determinate Nix needs nix.enable = false in the host config — it manages its own daemon, which conflicts with nix-darwin's own Nix management.
  • fonts.packages isn't shared the way hosts/common/default.nix shares it for NixOS — there's no darwin equivalent of that file, so each darwin host declares its own fonts (see hosts/txl/default.nix).
  • Nix-built GUI apps need an explicit ~/Applications symlink (home/darwin/apps.nix) or Spotlight/Dock/login-items/open -a won't find them. For anything needing Accessibility-style permissions (AeroSpace), expect to re-grant that permission after rebuilds where the package's store path changes.

Home manager

All user config is in home/, split into home/common (both OSes), home/linux, and home/darwin, applied via hmConfigLinux/hmConfigDarwin in flake.nix. Changes rebuild via the same deploy.sh — no separate home-manager switch needed.

Anything host- or OS-specific must not go in home/common. Where a value has to vary by host or platform inside a fish function, resolve it at runtime instead of at Nix-eval time — home/common/shell.nix's nrs/nrb do this, checking uname/hostname -s directly rather than baking in osConfig/pkgs.stdenv.isDarwin, since referencing osConfig from home-manager caused its own eval issues on darwin. For plain Nix config values (not fish functions), pkgs.stdenv.isDarwin/isLinux in a common module is fine (like zed.nix's theme) — just never in an imports list (see the darwin gotchas above). Where a whole module differs, put it in home/linux or home/darwin instead.