Nix journey part 2: replacing apt and brew
Even if I still cannot do much with nix, it still provides more advantages over other package managers:
- Multi-platform (mac, linux, etc.)
- Supports side-by-side installation of multiple versions of a package
- Makes it trivial to share development and build environments
- Nix ensures that installing or upgrading one package cannot break other packages
- It has the biggest database of packages (over 80.000 packages)
- I can run other people's commands, for example if I clone a repo and it says "run this nix command to have a development environment", then it doesn't matter if I don't know, I have already started using it.
A common situation I often run into, is writing shell scripts for linux and mac, where
sed are used.
On linux, they are called GNU
grep or GNU
sed, and they are not the same as in mac (freebsd version). Depending on the version, they may use different arguments.
We are going to see how can we avoid this by using
nix. Even without using complicated features, it can make your CI system more reproducible.
nix is 3 things at the same time: an OS, a package manager and a language.
This post is about the package manager. I don't have much interest in the language, yet. Though more and more, I think I'll have to learn it.
Let's start by acknowledging a source of confusion:
There is an old interface with counterintuitive commands (
nix-env -iA ...,
nix-shell -p ...), which I found hard to remember, and I don't get why the "commands" start with a dash (
-). I'm used to cli's doing
cli <command> [--options]. Nowadays, there's a new cli called just
nix. Let's see if we can do everything with it.
And make sure you have installed Nix: the package manager in your system. The installation is straightforward. I was personally blocked, because at some point in my dotfiles I was hardcoding the
PATH, making nix never appear 🤦♂️.
And enable flakes.
There's also a new installer by determine systems, which is quite good.
Install a package like on
nix profile install nixpkgs#htop
See also the profile install command reference.
In the old version of nix, we would run:
nix-env -iA nixpkgs.htop
Nix forces us to specify a "repository" (or "namespace") when installing a package (
nixpkgs), which could be different, like github. And I think this is a good thing. From my understanding, nix doesn't care where the package is, because each package has a lock file, tracking all the dependencies. Okay, it could be a problem if one of the "repositories" is down, but using
nixpkgs mainly and github for niche packages should be fine.
What are profiles?
Disclaimer: I may be wrong on this, I'm starting to understand it.
The way to see
profiles is like, "your user's packages".
nix profile links packages to your
~/.nix-profile/. You can specify other's profiles by using the flag
You can find more in the package-management section of the manual and the profile command reference
nix search nixpkgs#htop
Check the search command reference
We see again
nixpkgs, because we have to let nix know from where, and then what we are looking for (
htop in this case). To remember the word, I split it like this:
For example, I've made a flake package, hosted on github, and you can search what is offering, by specifying the "repository" only (no
nix search 'github:woile/wpa_passphrase_rs'
You can also search packages on nix search index, but the commands shown are for the old nix interface, using
Also, you can provide a regex like
nix search --help for more examples.
Now this is a bit tricky, to remove you cannot type
htop, you have to specify which dependency you want to clean. I think this is because you can have multiple versions of the same program. Also, one of your packages may depend on the version of another package, and if you also installed another version of the same package, and if you remove both, the original program that depends on one of them may break.
The solution to this is to list the installed packages in your profile, and then remove by position of said program.
nix profile list
nix profile remove 4
Check the profile remove command reference.
Open a package on a shell
This can be useful to test in isolation without installing a package in your profile.
nix shell nixpkgs#htop nixpkgs#gnused nixpkgs#youtube-dl sed --help htop --help youtube-dl --version CTRL+D # exit
Nix Package Tool (npt)
Because I'm not used to most of the seen commands, I built a thin abstraction on top of
nix called npt. Which aims to be a humble succesor to
apt. It also requires less characters to use it.
The installation, as we've seen before, can be done by running:
nix profile install 'github:woile/npt#npt'
And then run
npt --help and check the commands, I hope it helps the transition to nix.
Now you can install packages by doing:
npt install htop github:woile/wpa_passphrase_rs#wpa_passphrase # or npt i
It's still a work in progress, but a good start. I want to add the ability to show the executed nix commands, as a way of learning nix.
Remember when I said "even if you don't know much, someone else might", and having nix helps for this? and remember when I talked about my problems with
Turns out, nix can help in both of these situations, someone can write a reproducible shell script which you would execute, and even without knowing much, it would work.
A minor problem is that we cannot use flakes yet, meaning we cannot run
nix shell and instead, we have to rely on
nix-shell. But it's coming, see #5189, #4715.
In the meantime, let's try to solve the issue with what we have.
touch gnu-example.sh chmod +x gnu-example.sh vim gnu-example.sh
And paste the content of this script:
#! /usr/bin/env nix-shell #! nix-shell gnused gnugrep grep -V sed --version
./gnu-example.sh, it would work both on linux, mac and probably also on freebsd.
Take a look at this other example, you can install a specific version of python and even dependencies.
#! /usr/bin/env nix-shell #! nix-shell --pure -i python -p "python38.withPackages (ps: [ ps.django ])" import django print(django.__version__)
This opens the door to replace
pyenv and any
virtualenv you will ever need.
Imagine creating a nix file specific to your project with its dependencies, which loads a shell with the dependencies when you navigate to the project folder automatically. Yes, you can say goodbye to any version manager (
You can read more about building a
shell.nix in the nix.dev tutorial. But keep in mind that
shell.nix is being replaced by flakes.
Flakes are becoming the universal way of doing things in nix. Creating shells, build commands, compiling your source code or creating ISO images.
And there's a whole set of new tools making use of flakes that allow you to build dev shells, like devenv or flox.
An exciting future is ahead!
I hope you've learned something with this post, and if you liked it, please let me know in the comments section below or tag me on hachyderm @woile.