MacOS Nix Setup (an alternative to Homebrew) (2024)

I recently got a new Macbook, and began setting up the Nix package manager toinstall my developer toolset. I mainly did this to try and have a working setup withoutinstalling Homebrew. Since I ran into a few issues, I wanted to brieflydocument what I did and why in case others wanted to try the same.

Why Nix? (and why not Homebrew or MacPorts?)

The short answer: hype.

The long answer: I’ve been frustrated with Homebrew’s user experience for years now, andused this opportunity to start afresh. The default non-Homebrew answer is the venerableMacPorts, which has been around for quite a while. Most people who aren’tfunctional programming or build system nerds should probably use MacPorts, as it has beenaround long enough to have good support documentation floating around the internet.Unfortunately I’m a sucker for hermetic builds 1, so I decided to tryNix.

In addition, Nix has one cool feature I haven’t seen anywhere else: temporarily installingpackages using nix-shell. For example, I can install ripgrep inside a temporary shell,and the package is automatically cleaned up when I’m done:

nix-shell -p ripgrep

There’s a lot of cool stuff nix-shell can do, check out some more exampleshere.

Why not Homebrew?

If Homebrew works for you, then by all means keep using Homebrew! However, I’ve grownfrustrated with it. Homebrew has spent a lot of effort making a software delivery systemwork across many iterations of OSX/MacOS, and countless developers have installed brewas one of the first things on a new Mac. It is with this acknowledgement of the work theHomebrew developers have put into the software and its resulting success that I offerthese criticisms:

  1. Unpredictable command times. I never know if running brew install or brew upgradeis going to take 5 seconds or 20 minutes. This usually means knowing if a program ordependency is being downloaded as a prebuilt binary or compiled on the spot. It wouldbe nice to signal to the user if compilation is about to happen, so they can plan theinstall accordingly.

  2. Very slow brew update times. Homebrew’s core package database is agit repository, which is great for enabling collaboration. Nix usesthe same model, but the difference lies in how the clients get the packagedatabase: brew update does a git pull under the hood, while nix-channel --updatedownloads a compressed tarball each time the channel is updated. This means Homebrewupdates can rely on git and GitHub itself as an efficient distribution mechanism,getting delta updates “for free” without setting up extra infrastructure. However,this design choice means that the client has to maintain its own git repo –git gc can strike at any time, for example, and slow things downtremendously. It is also a nightmare for CI, where the lack ofan updated Homebrew git cache can negatively impact build times. Meanwhile,nix-channel --update runs are very predictable, even if a bit inefficient – you’redownloading a 16Mb tarball when the channel is updated, but that’s it.

  3. Bad interactions when packages are upgraded. I’m not sure exactly why this happens, butoccasionally when certain packages are upgraded (such as python from 3.7 to 3.8),related packages can break. Because Nix builds are hermetic,packages should all “work together” regardless of how the system was previously setup.

Why not MacPorts?

To be honest, MacPorts is probably just fine for your needs. I haven’t used it in forever,but my understanding is that it’s reliable and has plenty of built-up community knowledgeon how to fix things. Take a look at it and see if it fits your needs! I also quicklyfound this post which details some differences between it andHomebrew. But hey, if you like adventure, give Nix a shot!

Why not Nix?

I felt it was honest to include a section like this.

  1. I haven’t done a deep evaluation, but my impression is that Nix is the least documentedand least mature of the bunch. Expect to do a bit more digging to solve issues, butonce you get started it generally just works.

  2. Workarounds are currently needed for Catalina and above, especially if you have anolder Mac without a T2 chip.

  3. You’ll need to understand a bit of the Nix Expression Language. It’snot as scary as it sounds, but you will have to edit a .nix file to install apackage (there is no CLI equivalent to brew install that I am aware of).

Installing Nix

Installing Nix requires two phases: installing Nix itself, and then installingnix-darwin. The installation methods I know of involve curling with aneventual sudo call inside the script2. You will have to do something extra ifyou’re running Catalina3 or above.

  1. Install Nix:

    • Pre-Catalina: curl -L https://nixos.org/nix/install | sh
    • Catalina with a T2 chip: sh <(curl -L https://nixos.org/nix/install) --darwin-use-unencrypted-nix-store-volume(according to the site, “unecrypted” is a misnomer as the chip will encrypt itanyway).
    • Catalina without a T2 chip: follow these instructions4.

    Make sure that nix-build is now in your PATH. You may have to source$HOME/.nix-profile/etc/profile.d/nix.sh in your shell’s rc file to get this towork.

  2. Install nix-darwin:

    nix-build https://github.com/LnL7/nix-darwin/archive/master.tar.gz -A installer./result/bin/darwin-installer

    You should now have darwin-rebuild in your PATH.

Using Nix

The basic workflow for using Nix is editing ~/.nixpkgs/darwin-configuration.nix and thenrunning darwin-rebuild switch to activate those changes.

Editing darwin-configuration.nix

Open up ~/.nixpkgs/darwin-configuration.nix with your favorite editor. Look atenvironment.systemPackages: this is the list of packages you’ll want to install.Nix lists are space-delimited (not comma-delimited). The packages listedthere come from the Nixpkgs channel you’re subscribed to. You can list what packages areavailable by running nix-env -qaP or searching Nixpkgs online. All thepackages are prepended with pkgs.; I used Nix’s with pkgs; clause to prepend that bydefault:

 environment.systemPackages = with pkgs; [ gitAndTools.gitFull byobu wget ];

Activating your changes

Once you’re done editing, run darwin-rebuild switch to install your new packages! If youmade an error, darwin-rebuild will let you know and your current environment will not beaffected.

Updating the package database

If you want to update the package database, you can run

nix-channel --update

Advanced usage

Nix will detect conflicts and error out, such as when two packages install the samebinary. This can happen when python37 and python38, for example, both want to create abinary called pydoc3. To resolve this, you can call lowPrio to declare a package lowpriority and have the other package win.

 environment.systemPackages = with pkgs; [ python37 (lowPrio python38) ];

(As a side note: once you’ve installed both, look at how quickly you can uninstall andreinstall each package. It takes between 1 and 2 seconds to uninstall or reinstallpython3.7, which in my opinion is ridiculously fast.)

Further reading

I have to admit that I only have a shallow knowledge of Nix, and the information abovehas made it sufficient as a daily replacement for Homebrew. However, there is a richecosystem around Nix that you may want to explore further. Here are a few links to learnmore:

Good luck and have fun!

I hope this guide was helpful! Thanks to the Nix team for making such a cool packagemanager. As I’m relatively new to Nix, feel free to contact me if there’s something I gotwrong or could have explained more clearly. Good luck and have fun with Nix!

  1. From the Google SRE book: a build that is “insensitive tothe libraries and other software installed on the build machine.” This greatlyincreases reliability, because it means that whatever you have installed on yourcomputer is less likely to affect the build process and the resulting program. This issimilar to Dockerizing an application, but less extreme and lessresource-intensive to run. ↩︎

  2. This is just as risky as the classic curl | sudo sh.Unfortunately I can’t find another way to easily install Nix, so I guess you candownload https://nixos.org/nix/install and compare its signature beforerunning it. ↩︎

  3. Catalina gets a lot of shade for its read-only root filesystem and signedbinaries, but I think it’s a step forward for general purpose computing. What I objectto is that signed binaries must be signed with registered Apple developer accounts todistribute software, and these accounts cost money (anyone can run their own softwarewith the appropriate settings, but distributing software effectively needs an Appledeveloper account). It would be nice if that was a bit distributed, so anyone couldsign and Apple maintained a reputation database or something. I’m annoyed at Apple formixing good security and OS maintenance practices with total, walled-garden lockdown.Admittedly, the web has a lot of the same security benefits, but we’re not at apoint yet where web apps can compete with native applications. Hopefully we’ll getthere one day. ↩︎

  4. Thanks Philipp for figuring all this out and writing it down! ↩︎

MacOS Nix Setup (an alternative to Homebrew) (2024)
Top Articles
Latest Posts
Article information

Author: Velia Krajcik

Last Updated:

Views: 6304

Rating: 4.3 / 5 (74 voted)

Reviews: 81% of readers found this page helpful

Author information

Name: Velia Krajcik

Birthday: 1996-07-27

Address: 520 Balistreri Mount, South Armand, OR 60528

Phone: +466880739437

Job: Future Retail Associate

Hobby: Polo, Scouting, Worldbuilding, Cosplaying, Photography, Rowing, Nordic skating

Introduction: My name is Velia Krajcik, I am a handsome, clean, lucky, gleaming, magnificent, proud, glorious person who loves writing and wants to share my knowledge and understanding with you.