- Kloudnative
- Posts
- Is Nix a Better Alternative to Homebrew for Mac Package Management?
Is Nix a Better Alternative to Homebrew for Mac Package Management?
Explore how Nix enhances package management and system configuration on macOS, offering a more streamlined and flexible solution.
When you search online, you'll often see that:
Nix is a purely functional programming language.
Nix is a package manager.
Nix (Nixpkgs) is a package repository with package definitions written in the Nix language.
NixOS is a Linux distribution.
In this article, I'll show you how I'm using the Nix package manager and Nixpkgs repository to install packages and configure my new Mac.
Why Nix?
After a week with Nix, I've found it's excellent for installing CLI packages, Mac applications, settings, and more in a declarative way. This means you can pull your .dotfiles from GitHub, and let Nix configure everything for you automatically.
Nix supports many packages (nixos.org/packages) and, best of all, you can reuse your Nix config across other OS environments.
Kloudnative is committed to staying free for all our users. We kindly encourage you to explore our sponsors to help support us.
There’s a reason 400,000 professionals read this daily.
Join The AI Report, trusted by 400,000+ professionals at Google, Microsoft, and OpenAI. Get daily insights, tools, and strategies to master practical AI skills that drive results.
☝️ Support Kloudnative by clicking the link above to explore our sponsors!
Install Nix
To install Nix on your Mac, run:
sh <(curl -L https://nixos.org/nix/install)
For more detailed information, visit nixos.org/download.
A unique feature of Nix is that it doesn't install packages directly into your main system. Instead, it creates a separate volume, making it easy to add or remove packages. Nix also supports versioning, so you can roll back if something goes wrong — more on that in a future article.
To verify your installation, try running neofetch with nix-shell.
Let's try another command — what if we run neofetch on its own? I'll leave it to you to explore. As I mentioned earlier, Nix doesn't install packages directly onto your machine.
Configure Nix
Now let's configure Nix. Start by creating the config directory:
mkdir ~/.config/nix
We'll use nix-darwin with flakes. You can learn more about it on GitHub.
Run this command to initialize the flake.nix file:
cd ~/.config/nix
nix flake init -t nix-darwin - extra-experimental-features "nix-command flakes"
Once flake.nix is created, open it in your editor of choice. I use Vim, but feel free to use your favorite IDE.
If you're on Apple Silicon, update the line:
nixpkgs.hostPlatform = "x86_64_darwin"
to
nixpkgs.hostPlatform = "aarch64-darwin"
This change is necessary to ensure compatibility with Apple Silicon.
To install nix-darwin, run:
nix run nix-darwin --extra-experimental-features "nix-command flakes" -- switch --flake ~/.config/nix#m3mac
You can check if it's installed by running which darwin-rebuild:
After the installation, apply any system changes by running:
darwin-rebuild switch - flake ~/.config/nix
Make sure to re-run darwin-rebuild whenever you add more packages or configurations to flake.nix.
Installing Packages
Visit search.nixos.org/packages to find the packages you need. In future articles, I'll dive deeper into configuring flake.nix to install Mac applications, specific Brew packages, and customize Mac settings.
Let's dive deeper into the fluxe.nix file
My config file
You can check my config file here: [.nix]
{
description = "Chris Darwin Nix Configuration";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
nix-darwin.url = "github:LnL7/nix-darwin";
nix-darwin.inputs.nixpkgs.follows = "nixpkgs";
nix-homebrew.url = "github:zhaofengli-wip/nix-homebrew";
};
outputs = inputs@{ self, nix-darwin, nixpkgs, nix-homebrew }:
let
configuration = { pkgs, config, ... }: {
nixpkgs.config.allowUnfree = true;
# List packages installed in system profile. To search by name, run:
# $ nix-env -qaP | grep wget
environment.systemPackages =
[
pkgs.go
pkgs.rustup
pkgs.oh-my-posh
pkgs.alacritty
pkgs.mkalias
pkgs.neovim
pkgs.tmux
pkgs.neofetch
pkgs.git
];
homebrew = {
enable = true;
taps = [
"FelixKratz/formulae"
];
brews = [
"mas"
"borders"
];
casks = [
#"the-unarchiver"
"sf-symbols"
"font-hack-nerd-font"
];
masApps = {
#"Yoink" = 457622435;
};
onActivation.cleanup = "zap";
};
fonts.packages = [
(pkgs.nerdfonts.override { fonts = [ "JetBrainsMono" ]; })
];
system.activationScripts.applications.text = let
env = pkgs.buildEnv {
name = "system-applications";
paths = config.environment.systemPackages;
pathsToLink = "/Applications";
};
in
pkgs.lib.mkForce ''
# Set up applications.
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 src; do
app_name=$(basename "$src")
echo "copying $src" >&2
${pkgs.mkalias}/bin/mkalias "$src" "/Applications/Nix Apps/$app_name"
done
'';
system.defaults = {
dock.autohide = true;
dock.persistent-apps = [
"/System/Applications/Launchpad.app/"
"${pkgs.alacritty}/Applications/Alacritty.app"
"/System/Applications/Mail.app"
"/System/Applications/Calendar.app"
"/Applications/Slack.app"
"/Applications/Notion.app"
"/Applications/Brave Browser.app"
];
finder.FXPreferredViewStyle = "clmv";
loginwindow.GuestEnabled = false;
NSGlobalDomain.AppleICUForce24HourTime = true;
NSGlobalDomain.AppleInterfaceStyle = "Dark";
NSGlobalDomain.KeyRepeat = 2;
};
# Auto upgrade nix package and the daemon service.
services.nix-daemon.enable = true;
# nix.package = pkgs.nix;
# Necessary for using flakes on this system.
nix.settings.experimental-features = "nix-command flakes";
# Create /etc/zshrc that loads the nix-darwin environment.
programs.zsh.enable = true; # default shell on catalina
# programs.fish.enable = true;
# Set Git commit hash for darwin-version.
system.configurationRevision = self.rev or self.dirtyRev or null;
# Used for backwards compatibility, please read the changelog before changing.
# $ darwin-rebuild changelog
system.stateVersion = 4;
# The platform the configuration will be used on.
nixpkgs.hostPlatform = "aarch64-darwin";
};
in
{
# Build darwin flake using:
# $ darwin-rebuild build --flake .#m3mac
darwinConfigurations."m3mac" = nix-darwin.lib.darwinSystem {
modules = [
configuration
nix-homebrew.darwinModules.nix-homebrew
{
nix-homebrew = {
enable = true;
# Apple Silicon Only
enableRosetta = true;
# User owning the Homebrew prefix
user = "chris";
autoMigrate = true;
};
}
];
};
# Expose the package set, including overlays, for convenience.
darwinPackages = self.darwinConfigurations."m3mac".pkgs;
};
}
1. Top-Level Metadata
description = "Chris Darwin Nix Configuration";
This simple line provides a description, useful for identifying what this configuration is for, especially if you're managing multiple configurations.
2. Input Sources
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
nix-darwin.url = "github:LnL7/nix-darwin";
nix-darwin.inputs.nixpkgs.follows = "nixpkgs";
nix-homebrew.url = "github:zhaofengli-wip/nix-homebrew";
};
This section defines external inputs, which are other repositories that contain Nix package definitions and configurations:
nixpkgs: A collection of Nix packages (pointed to the "unstable" branch for the latest versions).
nix-darwin: Adds support for macOS-specific configurations.
nix-homebrew: Integrates Homebrew, allowing you to install macOS apps not available in Nixpkgs.
3. Package Installation
environment.systemPackages = [
pkgs.go
pkgs.rustup
pkgs.oh-my-posh
pkgs.alacritty
pkgs.mkalias
pkgs.neovim
pkgs.tmux
pkgs.neofetch
pkgs.git
];
The systemPackages list contains essential packages that will be installed on your system. This setup includes programming languages (Go, Rust), CLI tools (Neovim, Tmux, Git), and system utilities (Neofetch, Alacritty).
4. Homebrew Integration
homebrew = {
enable = true;
taps = [ "FelixKratz/formulae" ];
brews = [ "mas" "borders" ];
casks = [ "sf-symbols" "font-hack-nerd-font" ];
masApps = { };
};
This section enables Homebrew integration:
Taps: Additional repositories.
Brews: CLI packages to install via Homebrew.
Casks: GUI applications and fonts.
masApps: Apps from the Mac App Store, customizable by specifying app IDs.
5. Font Configuration
fonts.packages = [
(pkgs.nerdfonts.override { fonts = [ "JetBrainsMono" ]; })
];
This block installs JetBrains Mono from the Nerd Fonts library, optimized for development and compatible with several terminals.
6. System Defaults
system.defaults = {
dock.autohide = true;
dock.persistent-apps = [ /* App list */ ];
finder.FXPreferredViewStyle = "clmv";
loginwindow.GuestEnabled = false;
NSGlobalDomain.AppleICUForce24HourTime = true;
NSGlobalDomain.AppleInterfaceStyle = "Dark";
NSGlobalDomain.KeyRepeat = 2;
};
This section defines system-wide settings:
dock.autohide: Hides the Dock automatically.
persistent-apps: Keeps frequently-used apps in the Dock.
Finder and UI settings: Sets Finder's view style, enables dark mode, enforces 24-hour time, and adjusts key repeat speed.
7. Nix Daemon Service
services.nix-daemon.enable = true;
This enables the Nix daemon, allowing root and non-root users to manage Nix packages in parallel.
8. Experimental Features
nix.settings.experimental-features = "nix-command flakes";
9. Zsh Shell Configuration
programs.zsh.enable = true;
Enables Zsh as the default shell, especially useful on macOS Catalina or later where Zsh is the default.
10. System Information
system.configurationRevision = self.rev or self.dirtyRev or null;
system.stateVersion = 4;
nixpkgs.hostPlatform = "aarch64-darwin";
These options provide version control:
configurationRevision: Tracks configuration changes.
stateVersion: Sets the system state version.
hostPlatform: Specifies Apple Silicon compatibility.
11. Building and Running the Configuration
darwinConfigurations."m3mac" = nix-darwin.lib.darwinSystem {
modules = [ configuration nix-homebrew.darwinModules.nix-homebrew ];
};
This wraps everything up, defining the configuration for m3mac and specifying it as a Nix-Darwin system. You can build it with:
darwin-rebuild switch - flake ~/.config/nix