nix-darwin Guide

This comprehensive guide covers using nix-darwin for native macOS system management with Nix and Home Manager integration.

Table of Contents

  1. Overview
  2. Installation
  3. Configurations
  4. Usage
  5. Customization
  6. Management
  7. Troubleshooting
  8. Advanced Usage

Overview

nix-darwin brings the power of NixOS to macOS, allowing you to:

Key Features

System Management:

Development Environment:

Security & Privacy:

Installation

Prerequisites

System Requirements:

Install Nix:

curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix | sh -s -- install

Quick Installation

Use the interactive installation script:

# Clone the template
git clone https://github.com/yourusername/nixos-template
cd nixos-template

# Run the installer
./scripts/install-nix-darwin.sh

The installer will:

  1. Detect your Mac’s architecture (Apple Silicon/Intel)
  2. Let you choose a configuration (Desktop/Laptop/Server)
  3. Install nix-darwin with the selected configuration
  4. Set up shell integration and management tools

Manual Installation

For more control over the installation process:

  1. Clone the template:

    git clone https://github.com/yourusername/nixos-template ~/.config/nix-darwin
    cd ~/.config/nix-darwin
    
  2. Install nix-darwin:

    # For Apple Silicon Macs
    nix run nix-darwin -- switch --flake .#darwin-desktop
    
    # For Intel Macs
    nix run nix-darwin -- switch --flake .#darwin-desktop-intel
    
  3. Set up shell integration:

    echo 'if [ -e /run/current-system/sw/bin ]; then' >> ~/.zprofile
    echo '  export PATH="/run/current-system/sw/bin:$PATH"' >> ~/.zprofile
    echo 'fi' >> ~/.zprofile
    

Configurations

Available Configurations

Desktop Configuration

Purpose: Full-featured desktop environment for development and daily use

Features:

Best for: Primary development machines, workstations, iMacs

Laptop Configuration

Purpose: Mobile-optimized for MacBook users

Features:

Best for: MacBooks, mobile development, travel setups

Server Configuration

Purpose: Headless development server setup

Features:

Best for: Development servers, CI/CD machines, headless setups

Architecture Support

Apple Silicon (M1/M2/M3):

Intel Macs:

Usage

Basic Commands

System Management:

# Apply configuration changes
darwin-rebuild switch --flake ~/.config/nix-darwin

# List system generations
darwin-rebuild --list-generations

# Rollback to previous generation
darwin-rebuild --rollback

# Update flake inputs
nix flake update ~/.config/nix-darwin

System Information:

# Show system information
darwin-info

# Show current configuration
darwin-rebuild --show-trace

Maintenance:

# Update system and flake
darwin-update

# Clean up old generations
nix-collect-garbage -d

# Optimize Nix store
nix store optimise

Home Manager Integration

Home Manager is integrated automatically and manages:

Home Manager Commands:

# Switch Home Manager configuration
home-manager switch --flake ~/.config/nix-darwin

# List Home Manager generations
home-manager generations

# Edit Home Manager configuration
code ~/.config/nix-darwin/hosts/darwin-desktop/home.nix

Homebrew Integration

Homebrew is managed declaratively through nix-darwin:

# In configuration.nix
homebrew = {
  enable = true;

  # Command-line tools
  brews = [
    "ffmpeg"
    "youtube-dl"
  ];

  # GUI applications
  casks = [
    "visual-studio-code"
    "docker"
    "firefox"
  ];

  # Mac App Store apps
  masApps = {
    "Xcode" = 497799835;
    "TestFlight" = 899247664;
  };
};

Customization

System Preferences

Configure macOS system preferences declaratively:

system.defaults = {
  # Dock settings
  dock = {
    autohide = true;
    tilesize = 48;
    show-recents = false;
  };

  # Finder settings
  finder = {
    AppleShowAllExtensions = true;
    ShowPathbar = true;
  };

  # Global settings
  NSGlobalDomain = {
    AppleInterfaceStyle = "Dark";
    KeyRepeat = 2;
    InitialKeyRepeat = 15;
  };
};

Adding Packages

System-wide packages (in configuration.nix):

environment.systemPackages = with pkgs; [
  git
  vim
  curl
  nodejs_20
];

User packages (in home.nix):

home.packages = with pkgs; [
  vscode
  firefox
  htop
];

Shell Configuration

Configure your shell in Home Manager:

programs.zsh = {
  enable = true;
  enableCompletion = true;

  shellAliases = {
    ll = "ls -la";
    grep = "grep --color=auto";
  };

  oh-my-zsh = {
    enable = true;
    theme = "robbyrussell";
    plugins = [ "git" "docker" "node" ];
  };
};

Development Environment

Set up development tools:

# Languages and runtimes
home.packages = with pkgs; [
  nodejs_20
  python311
  go
  rustc
];

# Git configuration
programs.git = {
  enable = true;
  userName = "Your Name";
  userEmail = "your.email@example.com";

  extraConfig = {
    init.defaultBranch = "main";
    pull.rebase = true;
  };
};

Management

Configuration Structure

~/.config/nix-darwin/
├── flake.nix                    # Main flake configuration
├── darwin/
│   ├── default.nix             # Base nix-darwin config
│   ├── system.nix              # macOS system settings
│   ├── homebrew.nix            # Homebrew integration
│   ├── networking.nix          # Network configuration
│   └── security.nix            # Security settings
└── hosts/
    ├── darwin-desktop/
    │   ├── configuration.nix   # Desktop system config
    │   └── home.nix            # Desktop user config
    ├── darwin-laptop/
    │   ├── configuration.nix   # Laptop system config
    │   └── home.nix            # Laptop user config
    └── darwin-server/
        ├── configuration.nix   # Server system config
        └── home.nix            # Server user config

Updating Your System

Regular updates:

# Update everything
darwin-update

# Or manually:
cd ~/.config/nix-darwin
git pull origin main
nix flake update
darwin-rebuild switch --flake .

Selective updates:

# Update specific input
nix flake lock --update-input nixpkgs

# Update without pulling git changes
nix flake update && darwin-rebuild switch --flake .

Managing Generations

List generations:

darwin-rebuild --list-generations

Switch to specific generation:

darwin-rebuild switch --switch-generation 42

Delete old generations:

# Delete generations older than 7 days
sudo nix-collect-garbage --delete-older-than 7d

# Delete all but current
sudo nix-collect-garbage -d

Version Control

Track your configuration with Git:

cd ~/.config/nix-darwin

# Make changes
vim hosts/darwin-desktop/configuration.nix

# Commit changes
git add .
git commit -m "Add new development tools"

# Test the changes
darwin-rebuild switch --flake .

Troubleshooting

Common Issues

Build Failures:

# Check flake validity
nix flake check

# Build with more verbose output
darwin-rebuild switch --flake . --show-trace

# Check system log
log show --last 10m --predicate 'process == "nix"'

Permission Issues:

# Fix Nix store permissions
sudo chown -R root:nixbld /nix
sudo chmod 1775 /nix/store

# Restart nix-daemon
sudo launchctl stop org.nixos.nix-daemon
sudo launchctl start org.nixos.nix-daemon

Path Issues:

# Check PATH
echo $PATH

# Reload shell configuration
source ~/.zprofile

# Check nix-darwin activation
cat /run/current-system/activate

Homebrew Integration Issues:

# Reset Homebrew state
brew cleanup
brew doctor

# Force reinstall Homebrew packages
darwin-rebuild switch --flake . --option pure-eval false

Performance Issues

Slow Builds:

# Use binary cache
echo "substituters = https://cache.nixos.org/ https://nix-community.cachix.org" >> ~/.config/nix/nix.conf
echo "trusted-public-keys = cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY= nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs=" >> ~/.config/nix/nix.conf

# Enable parallel builds
echo "max-jobs = auto" >> ~/.config/nix/nix.conf

Large Nix Store:

# Check store size
du -sh /nix/store

# Optimize store
nix store optimise

# Clean up
nix-collect-garbage -d

Recovery

System Won’t Boot:

# Boot from recovery partition
# In Terminal:
/nix/var/nix/profiles/system/activate

# Or rollback
darwin-rebuild --rollback

Complete Reset:

# Remove nix-darwin (destructive!)
sudo rm -rf /nix
sudo rm /etc/synthetic.conf
sudo rm /etc/nix/nix.conf

# Reinstall Nix and nix-darwin
curl -L https://nixos.org/nix/install | sh
# Then reinstall nix-darwin

Advanced Usage

Custom Modules

Create custom nix-darwin modules:

# darwin/custom-module.nix
{ config, pkgs, lib, ... }:

with lib;

{
  options = {
    custom.feature.enable = mkEnableOption "custom feature";
  };

  config = mkIf config.custom.feature.enable {
    environment.systemPackages = [ pkgs.custom-package ];
  };
}

Multiple Users

Configure multiple users:

home-manager = {
  useGlobalPkgs = true;
  useUserPackages = true;

  users = {
    alice = import ./home/alice.nix;
    bob = import ./home/bob.nix;
  };
};

Cross-Platform Configuration

Share configuration between NixOS and nix-darwin:

# shared/development.nix
{ pkgs, ... }:

{
  # Cross-platform development tools
  environment.systemPackages = with pkgs; [
    git
    vim
    nodejs
    python3
  ];
}

Integration with CI/CD

# .github/workflows/nix-darwin.yml
name: nix-darwin CI
on: [push, pull_request]

jobs:
  check:
    runs-on: macos-latest
    steps:
      - uses: actions/checkout@v3
      - uses: cachix/install-nix-action@v20
      - name: Check flake
        run: nix flake check
      - name: Build configuration
        run: nix build .#darwinConfigurations.darwin-desktop.system

Secrets Management

Integrate with agenix for secrets:

# secrets.nix
let
  user1 = "ssh-ed25519 AAAAC3...";
  users = [ user1 ];

  system1 = "ssh-ed25519 AAAAC3...";
  systems = [ system1 ];
in
{
  "secret1.age".publicKeys = users ++ systems;
}

Resources

Documentation

Community

Examples and Templates

Learning Resources

This guide provides comprehensive coverage of nix-darwin usage. For additional help with the template, run darwin-info or refer to the configuration files in ~/.config/nix-darwin/.