Introduction
Nix has been gaining significant attention in the Linux community, particularly for its innovative approach to package management and system configuration. While many are familiar with NixOS on Linux systems, fewer know about Nix Darwin, which brings similar capabilities to macOS. This guide was inspired mainly by the video Nix is my favorite package manager to use on macOS and will walk you through setting up Nix Darwin on a Mac Mini M1, transforming it from a standard macOS system into a declaratively managed development machine.
Prerequisites
Before we begin, you’ll need:
- A Mac Mini with M1 chip
- Administrative access to your machine
- Basic familiarity with terminal commands
- An Apple ID (for App Store installations)
Core Installation
Installing Nix Package Manager
First, we’ll install the Nix package manager, which forms the foundation of our setup. Open Terminal and run:
sh <(curl -L https://nixos.org/nix/install)Follow the prompts to complete the installation process. This will set up the basic Nix environment on your system.
Setting up Nix Darwin
Nix Darwin extends Nix’s capabilities to manage macOS-specific features. Here’s how to set it up:
- Create the configuration directory:
mkdir -p ~/.config/nix
cd ~/.config/nix- Initialize the Nix Darwin configuration with flakes:
nix flake init -t nix-darwin --extra-experimental-features "nix-command flakes"
sed -i '' "s/simple/$(scutil --get LocalHostName)/" flake.nix- Install the configuration:
nix run nix-darwin --extra-experimental-features "nix-command flakes" -- switch --flake ~/.config/nix- Verify the installation:
darwin-rebuild switch --flake ~/.config/nixAdding Nix Homebrew Support
Nix Homebrew integration allows us to manage Homebrew packages declaratively. Add the following to your flake.nix:
{
inputs = {
nix-homebrew.url = "github:zhaofengli-wip/nix-homebrew";
# ... other inputs
};
outputs = { self, nixpkgs, darwin, nix-homebrew, ... }: {
darwinConfigurations."mac-mini" = {
modules = [
nix-homebrew.darwinModules.nix-homebrew
{
nix-homebrew = {
enable = true;
enableRosetta = true;
user = "YOUR_USERNAME";
autoMigrate = true;
};
}
];
};
};
}Package Management Approaches
Nix Darwin offers several ways to install and manage software. Let’s explore each approach:
1. Nix Terminal Applications
For command-line tools, add them to your system packages in flake.nix:
environment.systemPackages = [
pkgs.neovim
# Add other packages here
];2. GUI Applications
GUI applications require special handling to appear in Spotlight. Add this configuration to make them accessible:
environment.systemPackages = [
pkgs.mkalias
];
system.activationScripts.applications.text = let
env = pkgs.buildEnv {
name = "system-applications";
paths = config.environment.systemPackages;
pathsToLink = "/Applications";
};
in pkgs.lib.mkForce ''
echo "setting up /Applications..." >&2
rm -rf /Applications/Nix\ Apps
mkdir -p /Applications/Nix\ Apps
find ${env}/Applications -maxdepth 1 -type l -exec readlink '{}' + |
while read -r src; do
app_name=$(basename "$src")
echo "copying $src" >&2
${pkgs.mkalias}/bin/mkalias "$src" "/Applications/Nix Apps/$app_name"
done
'';3. Non-Free Applications
Enable non-free applications by adding:
nixpkgs.config.allowUnfree = true;4. Homebrew Applications
Manage Homebrew casks through your configuration:
homebrew = {
enable = true;
casks = [
"firefox"
# Add other casks here
];
onActivation.cleanup = "zap";
onActivation.autoUpdate = true;
onActivation.upgrade = true;
};5. App Store Applications
Install App Store applications using their ID:
homebrew = {
masApps = {
"The Unarchiver" = 425424353;
# Add other apps here
};
};To find an app’s ID, either:
- Install
masvia Homebrew and usemas search "App Name" - Copy the ID from the App Store URL (e.g., from
https://apps.apple.com/app/name/id425424353)
System Configuration
Command Line Tools
Add this to handle Xcode Command Line Tools installation:
system.activationScripts.postActivation.text = ''
if ! /usr/bin/pgrep oahd >/dev/null 2>&1; then
echo "Installing Rosetta 2..."
/usr/bin/softwareupdate --install-rosetta --agree-to-license
fi
if ! /usr/bin/xcrun -f clang >/dev/null 2>&1; then
echo "Installing Command Line Tools..."
/usr/bin/xcode-select --install
fi
'';MacOS System Preferences
Customize macOS settings through your configuration:
system.defaults = {
dock.autohide = true;
# Add other preferences here
};Maintenance
Updating Packages
To update Nix packages:
nix flake updateHomebrew packages will update automatically if you’ve enabled autoUpdate and upgrade in your configuration.
Best Practices
Version Control
Keep your Nix configuration under version control:
- Initialize a Git repository in
~/.config/nix - Commit your changes regularly
- Consider backing up to a remote repository
Modularization
Split your configuration into logical modules by creating separate files in ~/.config/nix/modules/:
nix-core.nix: Core Nix settingsapps.nix: Application configurationssystem.nix: System preferences
Then import them in your main configuration:
modules = [
./modules/nix-core.nix
./modules/apps.nix
./modules/system.nix
];Troubleshooting
If you encounter the error path '/nix/store/.../file.nix' does not exist, ensure that:
- All new configuration files are tracked by Git
- Run
git addon new files before rebuilding - The file paths in your configuration are correct
Remember that while committing isn’t necessary, new files must at least be staged with Git for the Nix flake to recognize them.
Conclusion
With Nix Darwin set up on your Mac Mini M1, you now have a powerful, declarative way to manage your macOS system. This configuration provides reproducibility, version control, and easy system management across all aspects of your machine.