I am currently evaluating Nix as a replacement for Homebrew CLI apps in macOS1. Others have previously written about this.
My goal is to keep a sane learning curve and learn things on-the-fly, only as needed. Nix is a massive ecosystem and has so many batteries included and components (NixOS, NixPkgs, NixOps, Nix programming language, nix-shell, nix-env, nix-darwin, home-manager, …). The good news is that those components are for the most part modular, there’s no need to adopt them all in order to reap the benefits that Nix provides.
For now, I am only adopting nix-env
and nix-shell
, with no *.nix
config
files. This post covers nix-env
.
For simplicity, think of nix-env
as a package manager, akin to apk
,
pacman
, brew
, apt
, pkg
, etc.
Install a package
$ nix-env -i moreutils
installing 'moreutils-0.67'
building '/nix/store/jsp0l5ny3kx8p9lx9w9r0x159i9jjnn6-user-environment.drv'...
I see some guides using nix-env -iA
but -i
seems to suffice. We could
optionally specify the nixpkgs.
prefix:
$ nix-env -i nixpkgs.moreutils
error: selector 'nixpkgs.moreutils' matches no derivations
Oh no! Maybe that’s what the -A
is for?
$ nix-env -iA nixpkgs.moreutils
replacing old 'moreutils-0.67'
installing 'moreutils-0.67'
Indeed! Apparently that -A
thing stands for attribute. The only thing I know
is that there are both nixpkgs.*
and nixos.*
. But I don’t care about NixOS
at this point. I’ll just ignore -A
from now on, for the time being.
List installed packages
$ nix-env -q
moreutils-0.67
Easy! This actually gets displayed in my less
pager.
Upgrade installed packages
$ nix-env -u
Easy! At this point, I am not super confident whether that works as intended though. We will find out in a few days when there’s some update to one of my installed CLI applications. I’ve heard there’s something called nix channel to control that. Leaving it for another day though.
Update(2022-02-18): I learned that nix-env -u
is akin to apt upgrade
or
apk upgrade
. It upgrades installed packages to newer versions but only if it
is aware there are newer versions. To actually refresh the repositories à la
apt update
or apk update
, use nix-channel --update
.
Note: On macOS this needs to be sudo -i nix-channel --update
. See
issue.
Uninstall a package
$ nix-env --uninstall moreutils
uninstalling 'moreutils-0.67'
building '/nix/store/5k8rsf4cxg4iz7cqnqirpww6r97bwnqr-user-environment.drv'...
Easy!
Search for packages
$ nix-env -qaP '.*moreutils.*'
The .*
seems to be needed. It works if I omit them, but only if I write the exact package name (apparently called ‘derivation’ in Nix):
$ nix-env -qaP moreutils
nixpkgs.moreutils moreutils-0.67
If I write the wrong package name, the following happens:
$ nix-env -qaP moreutil
error: selector 'moreutil' matches no derivations, maybe you meant:
moreutils
It was helpful in this case, but I wouldn’t always count on that. It is a bit
annoying that there’s no nix search moreutils
command, but it seems that
nix-env
is very heavily tailored to use short flags, just like pacman
in
Arch Linux. I got used to pacman
, hopefully I can get used to the nix-env
short flags at some point.
Actually I tried it out and there is a nix search
command!
$ nix search moreutils
error: experimental Nix feature 'nix-command' is disabled; use '--extra-experimental-features nix-command' to override
This isn’t very promising though. How come searching is experimental?! Anyway, I can live with the nix-env
form for now.
These are the 5 basic package management operations that I needed to bootstrap my dev environment. Without putting much effort on it, my initial list of package looks like this:
$ nix-env -q
atool-0.39.0
bash-interactive-5.1-p12
coreutils-9.0
exa-0.10.1
fpp-0.9.2
fzf-0.29.0
git-2.34.1
htop-3.1.2
hugo-0.92.0
jq-1.6
less-600
moreutils-0.67
ncdu-1.16
perl5.34.0-ack-3.5.0
ranger-1.9.3
stow-2.3.1
tmux-3.2a
tree-1.8.0
vim-8.2.4186
watch-procps-3.3.16
wget-1.21.2
zoxide-0.8.0
Those were very intuitive to find, with the exception of ack
and bash-interactive
:
bash
is a bit odd because Nix splits it into two packages: a non-interactive version and an interactive version. I have no idea why. My~/.bashrc
wrecked havoc with the non-interactive version.ack
is very oddly named. Really. Also:nix-env -i ack
doesn’t work, butnix-env -iA nixpkgs.ack
does. I suspect it will be hard to ignore-A
in the future.
Strictly speaking there’s nothing special about macOS in this context. The same setup can also be used in Linux distributions, for example, Debian or Ubuntu. In fact, this is what I did at $DAYJOB, because relying solely on Debian for package management is a very big limitation. I find that Nix complements the Debian repositories very well, the same way that it does for macOS. ↩︎