A Nix Flake managing NixOS, macOS, and Home Manager across all my systems from a single repo. The interesting bit is the architecture: every module is imported everywhere, and each module decides for itself whether to activate based on host metadata. No import lists to maintain, no per-host module selections - just drop a self-gating module in a directory and every relevant host picks it up automatically. If you're starting your own Nix configuration, I'd recommend https://github.com/Misterio77/nix-starter-configs as a foundation. 👍️ This repo is the deep end.
These computers are managed by this Nix flake ❄️
| Hostname | Board | CPU | RAM | Primary GPU | Secondary GPU | Role | OS | State |
|---|---|---|---|---|---|---|---|---|
malgus |
Framework Desktop Mainboard | AMD Ryzen AI Max+ 395 | 128GB | AMD Radeon 8060S | 🖥️ | ❄️ | 🚧 | |
zannah |
Framework Desktop Mainboard | AMD Ryzen AI Max+ 395 | 128GB | AMD Radeon 8060S | 🖥️ | ❄️ | 🚧 | |
sidious |
ThinkPad P1 Gen 1 | Intel Xeon E-2176M | 64GB | NVIDIA Quadro P2000 Max-Q | Intel UHD Graphics P630 | 💻️🎭️ | ❄️ | ✅ |
palpatine |
💻️🎭️ | 🪟 | ✅ | |||||
bane |
Framework 16 | AMD Ryzen 7 7940HS | 96GB | AMD Radeon 780M | 💻️ | ❄️ | ✅ | |
tanis |
ThinkPad Z13 Gen 1 | AMD Ryzen 5 PRO 6650U | 32GB | AMD Radeon 660M | 💻️ | ❄️ | ✅ | |
felkor |
ThinkPad X13 Gen 2 | AMD Ryzen 5 PRO 5650U | 16GB | AMD Radeon Vega 7 | 💻️ | ❄️ | 🚧 | |
shaa |
ThinkPad T14s Gen 1 | AMD Ryzen 5 PRO 4650U | 16GB | AMD Radeon RX Vega 6 | 💻️ | ❄️ | ✅ | |
atrius |
ThinkPad T495s | AMD Ryzen 7 3700U | 16GB | AMD Radeon Vega 10 | 💻️ | ❄️ | 🚧 | |
momin |
MacBook M3 Pro | 11-core Apple M3 Pro chip | 36GB | 14-core GPU | 💻️ | 🍏 | ✅ | |
steamdeck |
Steam Deck 64GB LCD | Zen 2 4c/8t | 16GB | 8 RDNA 2 CUs | 🎮️ | 🐧 | ✅ | |
crawler |
QEMU | - | - | VirGL | 🐄 | ❄️ | ✅ | |
dagger |
QEMU | - | - | VirGL | 🐄 | ❄️ | ✅ | |
defender |
Lima | - | - | - | 🐄 | 🐧 | ✅ | |
fighter |
Lima | - | - | - | 🐄 | 🐧 | ✅ | |
revan |
Z390-DESIGNARE | Intel Core i9-9900K | 64GB | Intel UHD Graphics 630 | NVIDIA T1000 | ☁️ | ❄️ | 🚧 |
malak |
B360 HD3P-LM | Intel Core i7-8700 | 128GB | Intel UHD Graphics 630 | - | ☁️ | ❄️ | ✅ |
maul |
TRX40-DESIGNARE | AMD Ryzen Threadripper 3970X | 256GB | NVIDIA RTX 3090 | NVIDIA RTX 2080Ti (22GB) | ☁️ | ❄️ | 🚧 |
Workstation and server host names are Sith Lords and the virtual machines are named after TIE fighter series. Dual boot systems have the NixOS install named a Sith Lord and the "other" OS named after their public-facing persona.
Key
- 🎭️ : Dual boot
- 🖥️ : Desktop
- 💻️ : Laptop
- 🎮️ : Games Machine
- 🐄 : Virtual Machine
- ☁️ : Server
- 🧟 : Not in service
As featured on Linux Matters podcast! 🎙️ I am a presenter on Linux Matters and this configuration was featured in Episode 7 - Immutable Desktop Linux for Anyone.
Most NixOS configurations use selective imports - each host cherry-picks which modules to include. This flake does the opposite.
Every module is imported by every host. Modules decide internally whether to activate, based on typed host metadata. I call this the "broadcast-and-gate" pattern, and it changes how you think about composing NixOS configurations.
The _mixins directories contain modules that are imported universally. Each module uses lib.mkIf with metadata from the noughty module system to decide whether it should do anything:
# This module activates itself on workstations. Servers and VMs ignore it.
{ config, lib, ... }:
lib.mkIf config.noughty.host.is.workstation {
boot.plymouth.enable = true;
}A module whose condition is false evaluates to nothing - zero cost, zero side effects. The Nix module system handles this natively.
Conditions can be as specific as you need: workstation vs server, laptop vs desktop, GPU vendor, display layout, user identity, freeform tags. Modules can combine conditions too - "only on Martin's workstations that have an NVIDIA GPU" is a one-liner.
Every host is registered in the system registry (lib/registry-systems.toml, read by flake.nix) with its properties: what kind of system it is, its platform, form factor, GPU vendors, displays, and freeform tags. The noughty module system turns this registry into typed, overridable NixOS options under config.noughty.*, with derived booleans like host.is.workstation, host.is.laptop, and host.gpu.hasNvidia computed automatically.
Adding a new feature = drop a directory containing a self-gating module. No import lists to edit. No other files to touch. Every host that matches the condition picks it up on next build.
Adding a new host = add a registry entry to lib/registry-systems.toml and create a hardware config. That's it. The new host automatically gets the right desktop, GPU drivers, services, shell, everything - because the modules gate themselves based on the host's properties, not its name.
Host-specific directories (nixos/vader/, nixos/sidious/, etc.) contain only hardware: disk layouts and kernel modules. All behaviour lives in the self-gating modules reacting to host properties.
The full noughty option reference, helper functions, and usage patterns are documented in lib/noughty/README.md.
Directory tree
.
├── common
│ └── default.nix
├── darwin
│ ├── _mixins
│ │ ├── desktop
│ │ └── features
│ ├── momin
│ └── default.nix
├── home-manager
│ ├── _mixins
│ │ ├── desktop
│ │ ├── development
│ │ ├── filesync
│ │ ├── scripts
│ │ ├── services
│ │ ├── terminal
│ │ └── users
│ └── default.nix
├── lib
│ ├── noughty
│ │ └── default.nix
│ ├── default.nix
│ ├── flake-builders.nix
│ ├── noughty-helpers.nix
│ ├── registry-systems.toml
│ └── registry-users.toml
├── nixos
│ ├── _mixins
│ │ ├── console
│ │ ├── desktop
│ │ ├── hardware
│ │ ├── network
│ │ ├── policy
│ │ ├── scripts
│ │ ├── server
│ │ ├── users
│ │ └── virtualisation
│ ├── atrius
│ ├── bane
│ ├── crawler -> dagger
│ ├── dagger
│ ├── felkor
│ ├── malak
│ ├── maul
│ ├── nihilus
│ ├── phasma
│ ├── revan
│ ├── shaa
│ ├── sidious
│ ├── tanis
│ ├── vader
│ └── default.nix
├── overlays
│ └── default.nix
├── pkgs
│ └── default.nix
├── secrets
│ └── secrets.yaml
├── flake.nix
└── justfile
| Directory | Purpose |
|---|---|
common/ |
Shared configuration imported by both NixOS and nix-darwin: overlays, system packages, environment variables, shell settings |
darwin/ |
macOS system configuration and _mixins for Darwin-specific features |
home-manager/ |
Home Manager configuration and _mixins for user-level programs, dotfiles, and scripts |
nixos/ |
NixOS system configuration, _mixins for self-gating modules, and per-host hardware directories |
lib/ |
The noughty module system, flake-builders.nix for generating configs from the system registry, registry-systems.toml and registry-users.toml for host and user definitions, and pure helper functions |
overlays/ |
Custom overlays: local packages, modified packages, and nixpkgs-unstable access |
pkgs/ |
Custom local packages |
secrets/ |
Encrypted secrets managed by sops-nix |
CI/CD workflows in .github are Nix ❄️ supercharged ⚡️ by Determinate Systems: Install Determinate Nix, FlakeHub Cache, Flake Checker, and Update Flake Lock.
A fully "oxidised" 🦀 Modern Unix shell experience is provided by Fish shell 🐟️ with Starship 🚀 and a collection of tools that deliver a contempory UX to my terminal 🧑💻
The base system has a firewall enabled and also includes OpenSSH, sops-nix for secret management, Tailscale and, of course, a gloriously unrepentant modeless Neovim config that treats modal editing as Stockholm syndrome. (Fight me! 🥊)
Useful shell scripts I used to keep in muddle of git repos are now migrated to NixOS scripts and Home Manager scripts to provide a declarative, reproducible and shellcheck validated toolbox 🧰
Hyprland 💧 and Wayfire 🔥 desktop options are available. The font configuration is common for all desktops using Work Sans and Fira Code. The usual creature comforts you'd expect to find in a Linux Desktop are integrated such as Pipewire, Bluetooth, Avahi, CUPS, SANE and NetworkManager.
| Desktops | NixOS | Home Manager | Theme |
|---|---|---|---|
| 💧 Hyprland | Hyprland NixOS | Hyprland Home Manager | Catppuccin Mocha |
| 🔥 Wayfire | Wayfire NixOS | Wayfire Home Manager | Catppuccin Mocha |
- Boot off an .iso image created by this flake using
just iso(see below) 💿 - Put the .iso image on a USB drive, I use USBImager
- Boot the target computer from the USB drive
- From a trusted workstation, inject tokens to the ISO host:
This sends the SOPS age keys to the live environment. Both age keys are hard requirements - the install will abort without them. FlakeHub authentication is handled interactively during install via
just inject-tokens <ip-address>
determinate-nixd login. Ifdeterminate-nixdis authenticated, the installer uses FlakeHub Cache for a faster install; otherwise it builds locally. - SSH into the ISO host and run the installer:
The install script uses Disko to partition and format the disks, installs NixOS via
ssh nixos@<ip-address> install-system <hostname> [username]
nixos-install, copies the flake to~/Zero/nix-config, and chroots into the new system to activate the Home Manager configuration. - Make a cuppa 🫖
- Reboot 🥾
See install-system documentation for the full reference.
As Disko is used to declare the disk layout for all my NixOS hosts, each NixOS configuration can be deployed to a remote host using nixos-anywhere.
The justfile includes an install recipe that wraps nixos-anywhere to simplify remote deployments.
For example, malak is a Hetzner dedicated server.
To deploy it, enable the Hetzner Rescue system and then run the following from one of my workstations:
just install malak <ip-address>Optional parameters: keep_disks="true" preserves existing disk partitions, and vm_test="true" runs a local VM test instead of deploying.
When the deployment is complete, the remote host will be automatically rebooted.
The just install recipe handles SOPS age keys (user and host), initrd SSH keys, and per-host SSH host keys automatically, decrypting them from sops secrets and injecting them into the target.
I keep my Home Manager configuration separate from my NixOS configuration, so after the NixOS configuration has been deployed, I SSH in to the remote host and activate the Home Manager configuration:
git clone https://github.com/wimpysworld/nix-config "$HOME/Zero/nix-config"
home-manager switch -b backup --flake "$HOME/Zero/nix-config"I clone this repo to ~/Zero/nix-config. NixOS and Home Manager changes are applied separately because I tend to iterate on the Home Manager configuration more frequently than the NixOS configuration.
gh repo clone wimpysworld/nix-config "$HOME/Zero/nix-config"
cd "$HOME/Zero/nix-config"This flake includes a justfile that provides convenient commands for building and applying configurations.
- ❄️ NixOS & macOS: Use
just hostto build and switch the NixOS or nix-darwin configuration.just build-hostto only build.just switch-hostto only switch.
- 🏠️ Home Manager: Use
just hometo build and switch the Home Manager configuration.just build-hometo only build.just switch-hometo only switch.
- 🌍️ All:
just buildto build both NixOS/nix-darwin and Home Manager configurations.just switchto switch to both NixOS/nix-darwin and Home Manager configurations.
Every push to main builds all configurations in CI and publishes them to FlakeHub Cache with full output paths. The apply commands pull these pre-built closures directly using the fh CLI, completely skipping local Nix evaluation and compilation. No flake evaluation, no derivation realisation, just fetch and activate.
- ⚡️ From FlakeHub Cache:
just applyto apply both NixOS/nix-darwin and Home Manager from FlakeHub Cache.just apply-hometo apply Home Manager only.just apply-hostto apply NixOS/nix-darwin only.
The tradeoff: you get whatever was last published from main. If you have local uncommitted changes, use just host/just home instead.
Daily ISO builds are available for download from this project's Releases, built automatically via GitHub Actions.
If you'd rather build your own, just iso builds the nihilus ISO image from this flake. It includes install-system for automated installation.
Live images will be left in result/iso/ and also copied to ~/Quickemu/nihilus/nixos.iso.
If nh, nom, just and home-manager are not available, here are the traditional ways to build and switch.
NixOS
sudo nixos-rebuild boot --flake $HOME/Zero/nix-config
sudo nixos-rebuild switch --flake $HOME/Zero/nix-config
nix build .#nixosConfigurations.{hostname}.config.system.build.toplevel
nix run github:nix-community/nixos-anywhere -- --flake '.#{hostname}' root@{ip-address}nix-darwin
nix run nix-darwin -- switch --flake ~/Zero/nix-config
nix build .#darwinConfigurations.{hostname}.config.system.build.toplevelHome Manager
home-manager build --flake $HOME/Zero/nix-config -L
home-manager switch -b backup --flake $HOME/Zero/nix-config
nix run nixpkgs#home-manager -- build --flake "$HOME/Zero/nix-config"
nix run nixpkgs#home-manager -- switch -b backup --flake "$HOME/Zero/nix-config"ISO
nix build .#nixosConfigurations.nihilus.config.system.build.isoImageThings I currently need to do manually after installation.
- 1Password - authenticate
- LastPass - authenticate
- Run
just detsys-login - Run
gh auth login - Keybase -
keybase login
- Atuin
atuin login -u <username>atuin sync -f
- Brave - enroll sync
- Chatterino - authenticate
- Discord - authenticate
- GitKraken
- Authenticate with GitHub
- Create Personal Profile
- Create Work Profile
- Grammarly - authenticate
- Maelstral -
maestral_qt - Matrix - authenticate
- Slack - authenticate
- Telegram - authenticate
- VSCode - authenticate with GitHub enable sync
- Wavebox - authenticate Google and restore profile
defender and fighter are Ubuntu virtual machines run under Lima for my Ubuntu MATE development and testing environments.
- Tools
install-cdebuginstall-chainctlinstall-wolfi-package-statusinstall-yam
- On Linux run
create-defendercreate-fighter
- On macOS run
- Run Docker Desktop to complete the setup.
- Create ntfy user and ACLs
sudo ntfy user add --role=admin <username>sudo ntfy access everyone <topic> rw
Some applications require manual configuration to apply the correct theme.
- Enable Stylus Sync to Dropbox in Brave to get Catppuccin userstyles and Enable Patch CSP
- Cider
- Open Cider
- Menu → Marketplace → Themes
- Find Catppuccin and your favorite flavor
- Click Install
- Discord OpenAsar
- Add Catppuccin CSS
/* mocha */
@import url("https://catppuccin.github.io/discord/dist/catppuccin-mocha.theme.css");
@import url("https://catppuccin.github.io/discord/dist/catppuccin-mocha-blue.theme.css");


