Nix solves a major technical challenge for us: having the right Python and the right
Node.js installations coexisting peacefully. This may not sound like much, but this way
we skip the land of
For local development, it's convenient. For actual deployments, it's critical.
But Nix is much bigger than that.
Your projects should guarantee three things: reproducibility, isolation, and native performance.
Your projects should be reproducible. Table stakes.
Checking out a version, tag or branch should declaratively state every requirement needed to run the application. For that specific project, on that specific branch, at that point in time.
Not just language-level dependencies like
react, but actual binaries and
language runtimes themselves. That's right, you should declare
python 3.9 and
jdk 11. Don't just document them, require them.
Check these requirements into your code.
But working on one project should not affect working on another. Your blog may depend on
python 3.9 and
go 1.17. And your consulting client has a site that requires
python 3.8. You should be able to switch between these seamlessly.
In fact, working on the same project with differing requirements should be possible.
You'll often collaborate on a long-lived branch to update a project to
Dare to live in a world where both branches can co-exist on your machine. Without having
to think about it.
This is true isolation. And Nix provides it. But... so does Docker, right?
You spent thousands of dollars on a machine. It runs quiet. It runs cool. It runs forever on battery. Why throw all that way and run your projects on Docker?
If you develop on a Mac: you're doing just that. Docker on MacOS is virtualized. And if you use Apple Silicon hardware, images can run even slower depending on the architecture.
Even keeping the development files in sync can be slow. Volume mounting is notoriously resource-intensive with Docker on Mac.
Moreover, running commands and scripting with Docker is clunky. A plain old shell experience is far nicer.
Finally: some will say running on Docker better reflects what is running on production — which does use containers. Dev / prod parity is a pillar of the 12-factor app, in fact.
I say maybe, but probably not. You're on different architectures at this point. Or worse, emulating them. Many cloud providers internally don't even use Docker at all.
Enter Nix. Using a single
shell.nix file, we declare everything our project needs.
In that point in time, on that branch, in that one instance of the project.
We list out
shellcheck and more.
It's happened before. You know it has. Your colleague is using
sed on a Mac. Another
sed on Ubuntu. And you are using
sed on a Mac but installed
get the Linux version. An absolute mess.
Nix standardizes everything. Once inside
nix-shell, everyone will have the same
sed, the same
grep and the same
find. And best of all: the same
Remember, this applies to our scripts too. Open up one of those quick, only for now
then I'll rewrite it later in Python 1000 line scripts. Yes,
convert-gcp-mp4s-to-gifs-and-upload-to-aws.sh, I'm looking at you.
Try to identify all the binaries that need to exist. You'll likely run into the regular
cast of characters:
wget. If you're lucky, you can expect most devs
and setups to have these,
OS-level differences aside.
But you need
gcloud installed, probably a version that supports their latest storage
options — the options your script uses. And — lest we forget — the
Last but not least, you need
Are you going to list all of these with setup instructions, identifying versions? Provide a Docker image? Just hope for the best? Write assertions at the top of the script ensuring they exist?
No, you're just going to list them in
And at the top of your script file, refer to it, using the
--pure flag. This will
ensure nothing unlisted is available to the script.
#! /usr/bin/env nix-shell #! nix-shell requirements.nix --pure -i bash # redacted ffmpeg -y -i "$filepath" -filter_complex "<filter options>" "$ANIMATED" aws s3 cp myfolder s3://mybucket/myfolder --recursive # redacted
New dev working on the project? Tell them to install Nix, check out the repository, and run the script. That's it. Nix will install and cache all the dependencies.