My personal Nix configuration managing macOS (via nix-darwin) and NixOS machines from a single flake.
Built with blueprint for auto-discovery of modules, home-manager for user-level config, nixvim for Neovim, agenix for secrets, and nix-homebrew for macOS GUI apps.
.
├── flake.nix # Inputs & blueprint entry point
├── secrets/ # agenix-encrypted secrets (.age files)
│ ├── secrets.nix # maps secret names to host SSH public keys
│ └── registry.nix # single source of truth for secret names
├── scripts/ # shell scripts sourced by zsh-functions
│ ├── dev.sh # dev shell selector
│ └── secret.sh # agenix secret manager
├── devshells/ # per-language dev shells (nix develop .#go, etc.)
│ ├── go.nix
│ ├── rust.nix
│ ├── python.nix
│ ├── nodejs.nix
│ ├── elixir.nix
│ ├── php.nix
│ └── full.nix
├── modules/
│ ├── nixos/common.nix # shared NixOS settings
│ ├── darwin/
│ │ ├── system.nix # macOS system defaults
│ │ └── homebrew.nix # Homebrew taps, brews, casks, mas apps
│ └── home/ # home-manager modules (shared across hosts)
│ ├── zsh.nix
│ ├── neovim.nix
│ ├── git.nix
│ ├── ghostty.nix
│ ├── zellij.nix
│ ├── starship.nix
│ ├── lazygit.nix
│ ├── zed.nix
│ ├── aerospace.nix # macOS window manager
│ ├── zsh-functions.nix # sources scripts/ for interactive commands
│ └── secrets.nix # agenix secret declarations
└── hosts/
├── homelab/ # HomeLab (x86_64-linux)
│ ├── variables.nix # host/user/network settings
│ ├── host-packages.nix # packages, home modules
│ ├── default.nix
│ ├── configuration.nix
│ └── hardware-configuration.nix
├── mini/ # Mac Mini (aarch64-darwin)
│ ├── variables.nix
│ ├── host-packages.nix
│ └── darwin-configuration.nix
└── vps/ # VPS (x86_64-linux)
├── variables.nix
├── host-packages.nix
├── default.nix
├── configuration.nix
└── hardware-configuration.nix
-
Clone the repo:
git clone https://github.com/tawsifaqib/nix-dotfiles.git ~/.nix-dotfiles -
Customise host variables — edit the file for your machine:
hosts/homelab/variables.nix— for NixOS (HomeLab)hosts/mini/variables.nix— for macOShosts/vps/variables.nix— for NixOS (VPS)
Change
host.name,user.name,user.email, SSH keys, timezone, etc. -
Pick your packages — edit the host-packages file for your host:
hosts/homelab/host-packages.nix— HomeLabhosts/mini/host-packages.nix— macOShosts/vps/host-packages.nix— VPS
-
Build & switch:
macOS:
darwin-rebuild switch --flake ~/.nix-dotfiles#miniNixOS:
sudo nixos-rebuild switch --flake ~/.nix-dotfiles#vps
Each host has a variables.nix that defines everything unique to that machine:
{
host = {
name = "mini"; # hostname
platform = "aarch64-darwin"; # or "x86_64-linux"
};
machine = {
sshPublicKey = "ssh-ed25519 AAAA..."; # used by agenix to encrypt secrets
};
nix = {
builder = "darwin-rebuild"; # "darwin-rebuild" or "nixos-rebuild"
};
user = {
name = "munza";
fullName = "Tawsif Aqib";
email = "hello@tawsifaqib.com";
homeDirectory = "/Users/munza";
};
paths = {
dotfiles = "~/.nix-dotfiles";
};
apps = {
defaultEditor = "nvim";
guiEditor = "zed"; # macOS only
defaultTerminal = "ghostty"; # macOS only
};
}Controls what gets installed and which home-manager modules are enabled:
{ pkgs, inputs }:
{
# Which home-manager modules to load (from modules/home/)
homeModules = with inputs.self.homeModules; [
git neovim zsh starship zellij lazygit secrets
];
# System-level packages
systemPackages = with pkgs; [
bat btop curl fd ripgrep tree nodejs python3 ...
];
# AI coding tools (from llm-agents input)
aiTools = with inputs.llm-agents.packages.${pkgs.stdenv.hostPlatform.system}; [
opencode pi
];
# macOS only — Homebrew casks, taps, brews
homebrew = {
casks = [ "ghostty" "zed" "google-chrome" "obsidian" ... ];
};
}Per-language development shells. Enter with:
nix develop .#go
nix develop .#rust
nix develop .#python
nix develop .#nodejs
nix develop .#elixir
nix develop .#php
nix develop .#fullTo add a new dev shell, create devshells/<lang>.nix:
{ pkgs }:
pkgs.mkShell {
packages = with pkgs; [
# language toolchain and tools
];
shellHook = ''
echo "Development Shell: <Lang>"
exec zsh
'';
}Blueprint auto-discovers files in devshells/ — no flake changes needed.
Secrets are encrypted to host SSH keys and stored safely in the repo.
All secret names live in secrets/registry.nix — the single source of truth. Both secrets/secrets.nix and modules/home/secrets.nix import this list, and environment variables are auto-generated from it.
# secrets/registry.nix
[
"github-access-token"
"brave-api-key"
"zai-api-key"
# add new secret names here
]Use the interactive secret command:
secret # interactive menu
secret add # add a new secret (updates registry.nix + creates .age file)
secret remove # remove a secret (removes from registry.nix)
secret update # edit an existing secret
secret rekey # rekey all secrets (e.g. after adding a host)Add a new secret manually:
-
Add the name to
secrets/registry.nix. -
Create the encrypted file:
cd secrets && nix run github:ryantm/agenix -- -e my-secret.age
This opens your
$EDITORwith the decrypted content. Save and quit to re-encrypt. -
Commit the
.agefile — it's safe to push.
Secret names are automatically converted to env vars (e.g. github-access-token → GITHUB_ACCESS_TOKEN).
Add a new host to existing secrets:
When you add a new host, add its SSH public key to secrets/secrets.nix under allHosts, then rekey:
cd secrets && nix run github:ryantm/agenix -- --rekeyUse a secret in a module:
# In a config file
xdg.configFile."app/config.toml".text = ''
api_key = "${builtins.readFile config.age.secrets.my-secret.path}"
'';Environment variables are auto-generated — no need to set them manually.
-
Create
hosts/<name>/with:variables.nix— host-specific settingshost-packages.nix— packages and home-manager modulesdefault.nix— the default module loaders (NixOS/macOS)configuration.nix(NixOS) ordarwin-configuration.nix(macOS)hardware-configuration.nix(NixOS only, auto-generated)
-
If the host needs secrets, add its SSH public key to
secrets/secrets.nix. -
Build and switch with the appropriate builder command.
Shared across all hosts. Enable/disable per host via host-packages.nix. Each module is auto-discovered by blueprint.
Personal configuration — use freely as a reference or starting point.