I started learning Nix a few months ago, when it was introduced to the company I work for by some brilliant coworkers. I'm still learning and exploring this space, but I thought I'd share a few tips and resources that helped me start this journey to help newbies like me start working with this awesome tool.
What is Nix
Nix is a powerful package manager for Linux and other Unix systems that makes package management reliable and reproducible. It provides atomic upgrades and rollbacks, side-by-side installation of multiple versions of a package, multi-user package management and easy setup of build environments.
So yeah, this post talks about a package manager. Usually this is something not very exciting. I can feel readers just thinking "aren't you just happy with Brew?". The truth is that Nix solved so many problems well that it's very hard for me not to get excited about it!
Let's break down the features listed in the description above:
- package management: well if this wasn't a feature we wouldn't really talk about a package manager
- makes package management reliable and reproducible: here stuff starts to get interesting. With Nix stuff works on everyone's machine, not just yours. This is because of how packages are built. Nix will pull all the necessary dependencies for you and packages are usually guaranteed to not need anything else (it makes no assumptions on what you already have installed).
- atomic upgrades and rollbacks: for real, it's like having transactions but for installations. Because of how Nix works (more about it later), multiple versions of the same package can coexist in the system (!) so upgrading will just mean referencing the new version, rolling back referencing the old one. And for everything else, there is garbage collection :)
- side by side installation of multiple version of a package: i spoilered this in the point above. But this works really well. You no longer have to decide which version of
npmyou need in your system and you can even start ephemeral shells with specific versions of stuff.
- multi user package management: usually package managers install stuff in user space. Nix normally install stuff so that it's available to multiple users in the system.
- easy setup of build environments: it's relatively easy to set up isolated build environments with the packages and versions you need. I say relatively because you'd still have to learn Nix, and the learning curve is steep. But once you learn it, it empowers you to do this. It's much harder to achieve this with "easier" package managers (so much that people starting creating docker images with their build environments, ugh).
I hope this list convinced you that learning Nix is worth it :) There are many more exciting features (like distributed binary caches, or the possibility to create small docker images and AMIs with the same language and only pull the runtime closures required), but now let's proceed with the learning stuff.
How to learn Nix
Learn how to install Nix
If you are on Linux or on a Mac Os X version 10.14 or earlier (NO CATALINA) , no problem, just follow the instructions here: https://nixos.org/nix/manual/#sect-multi-user-installation
I am linking to the multi user installation instructions because it seems to be the most frequently adopted in the community, so it might be easier to get help.
If you are on Mac Os X 10.15 or above (CATALINA or later):
- Install nix via:
curl -fsSL https://nixos.org/nix/install | sh /dev/stdin --daemon --darwin-use-unencrypted-nix-store-volume
- Close and reopen the terminal to make sure the right environment is loaded.
Learn to use Nix as a your package manager replacement
This video will explain briefly how to use nix as a "normal" package manager: Nix as a Homebrew Replacement
I will refer to many other videos from the Nixology playlist created by Burke Libbey throughout this article. If you want to skip ahead and watch all of them they are a great resource!
Note: to search packages, the video mentions this link: https://nixos.org/nixos/packages.html?channel=nixpkgs-unstable
Learn how to use and create nix-shells
Nix shells are a very powerful tool to create isolated development environments. I started creating them for many of the projects I am working on (some projects even have more than one shell) and they truly are a blessing. No more fiddling with different versions of software required in different projects.
You can start a nix-shell in any project that contains a
shell.nix file (for example this blog) and you will be dropped into a shell which contains the dependencies you need to work. To learn how to create these files, check out the Learn how to write a derivation in Nix section.
You can also start random nix shells without those files, just by specifying the packages you need. For example
nix-shell -p nodejs-12_x will start a shell with node 12 installed, without polluting your global PATH.
You can also reference remote paths to start your shell. For example
nix-shell https://github.com/amarrella/blog/archive/master.tar.gz will start the nix-shell used to build this blog.
Automatic nix-shells with direnv
direnv is a software that lets you load and unload enviroment variables when entering and exiting a directory. In combination with a nix shell, this will allow you to get an isolated environment as soon as you
cd into the directory. Install direnv and nix-direnv.
To use it, create a
.envrc file in the directory together with the nix shell and add the following line:
That's it. To enable direnv in the directory, run
direnv allow and now every time you cd into that directory the environment is loaded.
Learn the Nix language
Nix has its own purely functional and (unfortunately) dynamically typed programming language. It's a quite simple language, designed specifically for the Nix package manager. You can take a tour of the language (you can read up to slide 23, the later slides are way more advanced and not really required): https://nixcloud.io/tour/
Learn how to write a derivation in Nix
From nix manual:
Packages are built from Nix expressions, which is a simple functional language. A Nix expression describes everything that goes into a package build action (a “derivation”): other packages, sources, the build script, environment variables for the build script, etc. Nix tries very hard to ensure that Nix expressions are deterministic: building a Nix expression twice should yield the same result.
I suggest first watching these 3 videos from Nixology to get an idea on what you can do with derivations:
- Packaging a Gem as a Nix derivation
- Using nix to prettify
lsoutput on macOS
- Fetching stuff from the internet using Nix derivations
Then when you have a general idea and you need to dig deeper Nix pills provides a good overview on how to build nix derivations.
Learn how to create derivations to package your code
There are several libraries that help you package your code depending on the programming language you are using. The nixpkgs manual links some of them but sometimes checking out what is in the community leads to easier solutions. For example for Haskell, I'd use haskell.nix.
Learn to create docker images with Nix
Nix is also an excellent way of creating small and reproducible docker images. The dockerTools documentation provides some reference and examples.
Learn how to set up your computer or servers with Nix
You can use Nix to manage your home directory and all your user's environment via home-manager. It is really refreshing having a home directory and user environment managed in a declarative way, with easy updates to new versions and the possibility of rolling back at any point.
You can check out these videos from Nixology to learn more:
- Installing home-manager
- Getting started with home-manager
- From nix-env to home-manager
- home-manager: reading the source
You can also use the power of Nix to manage everything that is installed on your machine by using NixOs as a linux distribution or installing nix-darwin on your macOs. Both follow the same principle: you configure your machine using a configuration file and you apply changes atomically with
darwin-rebuild. Also here you have the possibility to roll back changes at any point. Here you can check the nixos manual and nix-darwin manual.
If you are curious about my configuration, it's published on Github.
Getting help from the community
Check out the nix community page for many official links. I personally lurk on the discourse forum, on the #nix channel in the functional programming slack (invite here) follow Github issues on the nix and nixpkgs repositories.