nix-config
A single Nix flake for provisioning both NixOS hosts and non-NixOS systems (any Linux now; macOS via nix-darwin later) from one shared set of modules.
Layout
flake.nix— inputs (nixpkgs,home-manager) and outputs (nixosConfigurations,homeConfigurations,formatter,devShells)lib/—mkNixosandmkHomehelper functions that buildnixosConfigurations/homeConfigurationsentriesmodules/nixos/common.nix— shared NixOS-only system settings applied to every NixOS host: flakes enabled,tomuser (bash as the login shell), locale/timezone defaults, gc policy, sshd (key-only auth) with a firewall allowing port 22, and a GNOME desktop (GDM login, NetworkManager, PipeWire audio, CUPS+Avahi printing) — see belowmodules/home/— the shared, cross-platform home-manager profile (shell, editor, CLI tools, dev tools, dotfiles). The same modules are consumed whether activated via a NixOS host's home-manager module or standalonehome-manager switchusers/tom.nix— identity/profile file consumed by bothmkNixosandmkHomehosts/template/— a copy-source-only NixOS host skeleton; never wired intoflake.nixoutputs directly (excluded from discovery by name — see below). Copy it viascripts/bootstrap-host.sh(ornix run .#bootstrap-host) when provisioning a real machinescripts/bootstrap-host.sh— scaffolds a newhosts/<hostname>/from the template; exposed asapps.<system>.bootstrap-hostmodules/home/dotfiles.nix— opt-in personal dotfiles automation (see below)modules/home/bash-profile.nix— always-on~/.bash_profilebootstrap (see below)modules/home/editor.nix— Neovim provisioning; deliberately never writes to~/.config/nvim(see below)
Any directory under hosts/ other than hosts/template that contains a system file automatically becomes a real nixosConfigurations.<name> output — adding a host means dropping in a directory, not editing flake.nix.
Installing NixOS on a new machine
This flake does not partition disks for you — do that first, with the standard NixOS installer or manually.
- Partition and format disks; mount the target filesystems under
/mnt(including/mnt/bootfor the ESP if UEFI). - Get this repo onto the installer:
nix-shell -p git && git clone <your-remote-url> ~/nix-config(requires the repo already pushed to a remote — see Follow-ups below). - From
~/nix-config, scaffold the host:nix run .#bootstrap-host -- <real-hostname> --root /mnt --state-version <ver>--root /mnttells the script to read (or generate, vianixos-generate-config --root /mntif needed)hardware-configuration.nixfrom the freshly mounted install target — it never reads the live installer's own/etc/nixos, since--roothas no default and must always be given explicitly.--state-versionshould match the installer's NixOS release (e.g.24.05) and should never be changed after the fact. - Review
hosts/<real-hostname>/configuration.nix(boot loader choice, etc.) — the script prints this reminder along with the exact next commands. cd ~/nix-config && git add hosts/<real-hostname>(flakes only see git-tracked files).- If needed:
export NIX_CONFIG="experimental-features = nix-command flakes". nixos-install --root /mnt --flake ~/nix-config#<real-hostname>.- Reboot and remove the install media.
- Afterwards, clone the flake to a stable path (e.g.
/etc/nix-config) so future updates are justsudo nixos-rebuild switch --flake /etc/nix-config#<real-hostname>.
Desktop environment
Every NixOS host built from this flake boots into a GNOME desktop by default (GDM as the login manager), applied unconditionally in modules/nixos/common.nix rather than as a per-host opt-in. Necessary companions are enabled alongside it: networking.networkmanager (GNOME's own network settings UI), services.pipewire + security.rtkit (audio, including PulseAudio-compatible clients), and services.printing (CUPS) + services.avahi (nssmdns4, openFirewall) for printing and network/AirPrint printer discovery — openFirewall is required so mDNS discovery traffic isn't blocked by the port-22-only firewall this repo already enables. This is a system-level toggle only; per-user GNOME customization (dconf, Shell extensions) is out of scope.
Installing on a non-NixOS system (any Linux, or macOS once supported)
Non-NixOS hosts are unaffected by bootstrap-host — there's nothing per-host to scaffold. homeConfigurations has one generic entry per platform (tom@linux for x86_64-linux, tom@darwin for aarch64-darwin), shared by every standalone machine of that platform.
- Install Nix. Recommended: the Determinate Systems installer (flakes enabled by default). The official installer also works, but you'll need to add
experimental-features = nix-command flakestonix.confyourself. git clone <your-remote-url> ~/nix-config.- First run:
nix run home-manager/master -- switch --flake ~/nix-config#tom@linux(or#tom@darwinon macOS). After that,home-manager switch --flake ~/nix-config#tom@linux(or#tom@darwin) works directly.
This only touches your home directory — no sudo required.
Personal dotfiles (opt-in)
modules/home/dotfiles.nix can automatically clone a separate personal dotfiles repo to ~/dotfiles and symlink its top-level package directories into $HOME, GNU-Stow style (each package directory's contents mirror their target path — e.g. a package's .gitconfig links to ~/.gitconfig). It's opt-in and controlled by a single option:
home.dotfiles.repoUrl = "https://example.com/your/dotfiles.git";
users/tom.nix sets this to https://git.tomvanderlee.com/dotfiles — the feature is active as soon as this flake is activated with home-manager switch.
Behavior notes: an existing ~/dotfiles checkout is never re-cloned or modified; every non-hidden top-level directory is treated as a stow package; one package's conflict with an existing file only skips that package (a warning is printed) rather than blocking the rest. Because ~/dotfiles/git/.gitconfig and ~/dotfiles/bash/.bashrc are expected to be the sole sources of git and bash configuration once stowed, this repo's own programs.git/programs.bash home-manager management has been removed — git itself is still installed via modules/home/cli-tools.nix, and bash ships with both macOS and NixOS regardless of whether repoUrl is set.
Editor (Neovim)
modules/home/editor.nix installs Neovim as the default editor ($EDITOR/$VISUAL, plus a vim alias), and provisions a C compiler (pkgs.stdenv.cc) and the tree-sitter CLI so natively-built plugins can compile. It deliberately sets programs.neovim.sideloadInitLua = true, which stops home-manager from writing anything to ~/.config/nvim/init.lua — that path is owned exclusively by the personal dotfiles repo's neovim Stow package (lazy.nvim + plugins). Without sideloadInitLua, home-manager's own generated init.lua permanently conflicts with that Stow package and it gets silently skipped (per the dotfiles automation's skip-on-conflict behavior above), so plugins never load. Don't add programs.neovim.extraConfig/plugins/anything else that writes into ~/.config/nvim here — it would reintroduce the same conflict.
Login shell bootstrap
NixOS and most other Linux distros don't ship a ~/.bash_profile that sources ~/.bashrc, so login shells never pick up your bash config. modules/home/bash-profile.nix creates one for you — but only if ~/.bash_profile doesn't already exist. If it's already there (any file or symlink), it's left completely untouched; home-manager never edits or removes it. This is always on, on every platform (Linux and macOS), and isn't gated by home.dotfiles.repoUrl — it works whether or not you use the personal dotfiles automation above.
Developer tooling
modules/home/dev-tools.nix provisions the developer's most-used CLI tools: gh, tmux, htop, yq-go, tree-sitter, docker, docker-compose, kubectl, awscli2. The container/cloud entries (docker, docker-compose, kubectl, awscli2) are client/CLI tools only — the actual container runtime (OrbStack/Docker Desktop on macOS) and any cloud account configuration stay outside Nix's control; these just give you a consistent CLI version to talk to whatever runtime/account is already set up.
terraform was considered but deliberately left out: recent versions are unfree-licensed (HashiCorp's BSL), which would require either nixpkgs.config.allowUnfree = true (flake-wide, not just for terraform) or substituting opentofu. Neither was wanted for now.
Shell and prompt: bash is the primary managed shell (matching where the real shell config already lives — ~/dotfiles/bash/.bashrc). modules/home/shell.nix only provisions the liquidprompt package; its configuration and activation are entirely owned by ~/dotfiles/liquidprompt/, same as git and bash. There is no Nix-managed starship or direnv — both were removed; per-project environments are left entirely to your existing pyenv/nvm/rustup setup rather than a Nix-managed alternative.
Development
nix fmt— format all.nixfiles withnixfmt-rfc-style.nix develop— a shell withstatixanddeadnixfor linting.nix flake check— validateshomeConfigurations."tom@linux",apps.bootstrap-host, and the other outputs defined here (there are no realnixosConfigurationsuntil a host is scaffolded — see Follow-ups).
Follow-ups (not covered by this change)
- Push this repo to a remote — required before
nixos-installcangit cloneit during a real install. - Add a real NixOS host once hardware has been partitioned (see workflow above).
- Add nix-darwin once a real Mac host is being configured.
- Add secrets management (e.g. sops-nix) — none is set up yet.
