
brew-nix: I just ditched Homebrew entirely
I have been experimenting on using Nix as a configuration
language for a year now. Nix, as a
configuration, does not limit to NixOS, but also allows configuring Apple (Mac)
machines possible via additional
nix-darwin
flake. As so many
influencers switch to Nix, I decided to jump onto the wagon too, albeit not
with the total understanding of the language. I stitched the scripts from
random places barely holding together to create a somewhat functional Nix
configuration, just so I can continue working as normal. I would say that I did
not understanding the language entirely (even today), and I probably missed the
full potential of the language.
The Current State of Homebrew
linkHomebrew is a package manager on MacOS. Basically, we can install apps via
terminal using brew
command directly. So, no downloading packages apps from
random websites and doing drag-and-drop actions; Homebrew will do those things
for us. Available applications ranges from open source software to popular
closed-source app from tech giants. I would say, at minimum, everyone with Mac
should have this program installed. The automation of installing graphical apps
alone is already impressive for me.
To list the already-installed apps by Homebrew, we can enter the command list
.
$ brew list
==> Casks
nikitabobko/tap/aerospace firefox localsend
alacritty gimp stolendata-mpv
audacity inkscape wireshark
bitwarden jellyfin-media-player zen
blender josm zotero
chromium libreoffice
Typical CLI apps will be called “Formulae”, and graphical apps will be called “Casks”.
So, when I have to install desktop apps to my machine, I can refer to Homebrew’s Casks most fo the time. From the open-source image editor GIMP to popular apps like Zoom, I can just type to install from terminal easily.
Homebrew to nix-darwin
linkWhen it was the time for me to express those applications in Nix expression, I
listed the applications like above, and then paste it somewhere in the Nix
options. In this case, nix-darwin
has the
option to
enable Homebrew integration, and also list the casks that I want to install.
So, if I add another application in the Nix list, nix-darwin
will trigger
Homebrew automatically, and Homebrew will install only the added app into the
machine.
homebrew = {
enable = true;
onActivation = {
autoUpdate = true;
cleanup = "uninstall";
upgrade = true;
};
casks = [
"alacritty"
"audacity"
"bitwarden"
# and so on ...
];
};
At this point, 99 percent of users will be satisfied on the result. Everything works as normal, (overkilled) nix config is working. However …
Problems
link- I have to install Homebrew by myself separately: Although there is an
option integrated into
nix-darwin
, it will not install Homebrew itself for you. I have to install Homebrew first before using these Nix configurations. That is another step I have to remember in the case I start with a clean Mac. - Homebrew setup is not idempotent: The way
nix-darwin
works is that it triggers Homebrew after it evaluates expressions. However,nix-darwin
and Homebrew are separate programs. If Homebrew fail to run (which can happen sometimes),nix-darwin
will not aware of the problem at all. If rebuilding the flake at the first time is not working due to errors from Homebrew, rebuilding the flake second time would usually be successful. This made the entire configuration not as functional as Nix advertised.
brew-nix
linkWhile I searched for the solution on solving the idempotent problem, I stumbled
upon a new flake called brew-nix
. I am not the person who add random flakes
just to solve one small problem, but I think the functionality of this flake is
so valuable, much like how Homebrew is basically the only MacOS package
manager.
The way brew-nix
works is that it still uses Homebrew’s repository as a
source, so it inherits the apps diversity Homebrew has and ensuring
compatibility with MacOS. Then, it downloads the apps to /nix/store
path and
symlinks them to application directory. We can see that the installation does
not use Homebrew at all; just downloads and symlinks. brew-nix
already does
the Homebrew’s job. Therefore, we do not need Homebrew at the first place, and
still get the same application with full integration of Nix!
First, I include their flakes.
inputs = {
# nixpkgs, nix-darwin, ...
brew-api = {
url = "github:BatteredBunny/brew-api";
flake = false;
};
brew-nix = {
url = "github:BatteredBunny/brew-nix";
inputs.brew-api.follows = "brew-api";
};
}
Then, I can add the module in nix-darwin
to expose the option.
darwinConfigurations = {
macair = nix-darwin.lib.darwinSystem {
system = "aarch64-darwin";
modules = [
+ brew-nix.darwinModules.default
# other modules
After we enable brew-nix
, all those casks will be accessible with prefix
brewCasks
.
brew-nix.enable = true;
environment.systemPackages = with pkgs; [
brewCasks.alacritty
brewCasks.audacity
brewCasks.bitwarden
# and so on ...
];
Finally, after doing darwin-rebuild
, all the applications will be shown as
symlinks under /Applications/Nix Apps
directory (also symlinked).
My Takes
linkAfter I migrated to brew-nix
completely, everything seems fine. I can use
applications like normal, which is surprising. Each flake update does not have
the Homebrew’s error problem anymore, so I am pretty satisfied right now.
The only problem I faced right now is the application state that is refreshed/wiped after every update. For example, my Firefox browser does not remember my default profile after I update the app, so I have to relink my profile to be the default one every time after the update. There might be some settings that will persist or relink the state data, but that is future me problem for now.
There is also a problem of the apps not showing up in MacOS Spotlight Search. I assumed it might be because of how the apps are symlinked, they are not indexed. Also, most importantly, Spotlight Search is bad, so I will blame this on MacOS and not the project.
Conclusion
linkDoes this mean that Homebrew is pretty much useless after this configuration?
Yes and No. I do not need to have Homebrew installed on my machine. Still, it
does not mean that the whole Homebrew project is obsolete. brew-nix
is still
relying on Homebrew repository.
I saw this project as a temporary solution to installing Nix applications in
MacOS. Many GUI MacOS applications can already be installed via nixpkgs
directly (without Homebrew repository). After I check my list of around 20
apps, around 15 can be installed directly nixpkgs
, 5 of them need to be
installed via brew-nix
. I am not sure what stop them from porting those
applications to nixpkgs
.
Mac without Homebrew, or even brew-nix
, is possible. Only time will tell.