Declarative macOS system configuration using Nix flakes, nix-darwin, and home-manager.
- Nix: Package management and system configuration
- nix-darwin: macOS-specific system configuration
- home-manager: User environment management
- Homebrew: GUI applications via nix-homebrew integration
GUI apps use Homebrew casks while CLI tools use Nix packages.
config/
├── flake.nix # Main entry point - defines all machine configurations
├── flake.lock # Locked dependency versions
├── common/ # Shared configurations (applied to ALL machines)
│ ├── darwin/ # macOS system settings (keyboard, fonts, Homebrew base)
│ └── home-manager/ # User environment (packages, dotfiles, shell config)
├── hosts/ # Machine-specific configurations
│ ├── atlas/ # Primary machine (user: manuel)
│ │ ├── configuration.nix # System-level packages, Homebrew casks
│ │ └── home.nix # User-level packages
│ └── cosmos/ # Secondary machine (user: manuel)
│ ├── configuration.nix
│ └── home.nix
├── assets/ # Standalone config files (tmux.conf, aerospace.toml, etc.)
├── nvim/ # Neovim configuration (Lua)
├── ghostty/ # Terminal emulator config
├── lazygit/ # Git UI config
└── gh/ # GitHub CLI config
The flake.nix defines multiple darwinConfigurations, each representing a machine:
darwinConfigurations."atlas" = nix-darwin.lib.darwinSystem {
modules = [
./common/darwin/default.nix # Shared macOS settings
./hosts/atlas/configuration.nix # Machine-specific system config
home-manager.darwinModules.home-manager
{
home-manager.users.manuel = import ./hosts/atlas/home.nix;
}
];
};- common/darwin/ - Applied first, sets base macOS defaults
- common/home-manager/ - Imported by each host's
home.nix, provides shared packages/dotfiles - hosts/{machine}/ - Machine-specific overrides and additional packages
- Create
hosts/{new-machine}/configuration.nixandhome.nix - Import
../../common/home-managerin the newhome.nix - Add a new
darwinConfigurations."{hostname}"block inflake.nix - Rebuild:
darwin-rebuild switch --flake .(setswitch --flake .#MACHINE-NAME, if host name is not equal to the name in the nix flake).
| File | Purpose |
|---|---|
common/home-manager/default.nix |
Main shared config: packages, git, zsh, tmux |
common/darwin/default.nix |
macOS system defaults and Homebrew base config |
hosts/*/configuration.nix |
Machine-specific Homebrew casks and system settings |
assets/tmux.conf |
Tmux keybindings and settings |
assets/aerospace.toml |
Tiling window manager config |
nvim/init.lua |
Neovim entry (uses Lazy plugin manager) |
- Shared packages go in
common/home-manager/default.nix - Machine-specific packages go in
hosts/{machine}/home.nixorconfiguration.nix - Homebrew casks (GUI apps) defined in host's
configuration.nix
xcode-select --installcurl -fsSL https://install.determinate.systems/nix | sh -s -- installThe Determinate Systems installer handles this automatically. If using the official installer, append to .zshrc:
if [ -e '/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh' ]; then
. '/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh'
fiIf you want darwin-rebuild to auto-detect your configuration:
sudo scutil --set LocalHostName atlas # or cosmos
sudo scutil --set ComputerName atlasOtherwise, specify explicitly with --flake .#atlas.
git clone <repo-url> ~/git/config
cd ~/git/config
# First build (uses hostname for auto-detection, or specify .#<machine>)
nix run nix-darwin --extra-experimental-features 'nix-command flakes' -- switch --flake .#MACHINE-NAMEwhere the machine name is set to one of the available machines (see [#Machines])
darwin-rebuild switch --flake .#MACHINE-NAMEnix flake update
darwin-rebuild switch --flake .#MACHINE-NAMEnix-shell --command zsh| Hostname | User | Purpose |
|---|---|---|
| atlas | manuel | Primary development machine |
| cosmos | manuel | Secondary machine |