Nix, the package manager

I know I said I would make this thread “in the next day or two” about a month ago. I am finally getting around to it. Sorry for the delay!

The Confusion

Lets get a bit of terminology out of the way. It is rather unfortunate, but nix can refer to a couple things within the ecosystem and they are sometimes used interchangibly.

Nix the package manager

As you have probably guessed, this is going to be mostly what my post is about. I will be giving some basic examples of how to actually use nix, and hopefully a handful of other people will chime in with their workflows on how to use it.

Nixpkgs

This is the default repository that nix runs against. You can find a lot of different packages here, and if there is something that you want that is not currently packaged, you have the ability to add it yourself!

NixOS

This is a linux based operating system built from the ground up to support nix.

Nix the programming language

This is the language used to describe and build nix packages.

The basics

For anyone that has not yet heard of nix, it is a purely functional package manager. It aims to be able to give reliable and reproducible builds. As mentioned previously, nixpkgs runs from a git repository, so it is possible to “pin” to the git ref that you want to build against. This is very useful if you have a team building a project with nix so that your entire team can be sure to be using the same version of all software.

You can use it along side your current installation of any other package manager(s) you may be using. It works by creating a /nix/store directory where it puts everything. An example in the directory will look like

cq8qrvg8s1jwcli4w2rnd4nlays35ikf-elixir-1.8.2

This is an installation for Elixir 1.8.2 that I have. cq8qrvg8s1jwcli4w2rnd4nlays35ikf is a hash of all of that packages inputs (including its dependency graph) in order to uniquely identify that package. I will come back to why this is important a little later.

Installation

Installation is very simple. On any Linux or MacOS machine, just run

$ curl https://nixos.org/nix/install | sh

as a user that is not root. You can find these instructions on the main page for Nix.

Installing and removing packages

You can install a package using the nix-env command line utility.

$ nix-env -i hello

With the above, you will install GNU Hello. To remove a packge, simply

$ nix-env --uninstall hello

The previous command will only unlink the package from your $PATH. To actually remove it, and all unused packages, you will need to run

$ nix-collect-garbage -d

The -d option will make it actually delete the packages and free your disk space.

If you would like to search for available packages, you can find most listed here.

Multiple of the same package

This is one of the killer features of Nix in my opinion. The ability to have multiple of the same package, even multiples of the same version, installed simultaneously. This is useful for when you have different projects that are configured differently (think C project with different switches to enable other features). This is the reason for the hash that prefixed the package name and version in the /nix/store path.

The hash also has a second function, in that it is a unique identifier. When you try to install a package, nix will calculate that hash and then ask nix’s cache whether or not it has something with that identifier. If it does, it will just download it and throw it into your /nix/store path. If it does not, it will just follow the build instructions in order to build your package. This is great because it means you will generally not have to wait for long compile times on larger packages.

Nix shell

Nix shell is a really handy tool if you want to test a package without bringing it into your global package set, or if you are working on a project that supports nix.

In order to test a package, you would simply

$ nix-shell -p elixir

If this is your first time running the command, it will download the current version of Elixir (current is dependent on the nix release channel you are currently following) and all of it’s dependencies. It will then drop you into a bash shell where you have access to elixir. You can test by running iex or any other binary that Elixir ships with.

If you were to run that command again, it will immediately drop you into the bash shell with Elixir because it is already downloaded.

Using it in a project

The easiest way to get started using nix in a simple elixir project would be to use the previous nix-shell command. It pulls in the basics required for building your project. This may work well enough for a while if you are the only person doing this. However, a better solution would be to build a basic shell.nix file. If you put that file in the root of your project, you can run $ nix-shell and it will automatically download any of the inputs it needs (in this case, just elixir) and drop you into a shell to start working on your project.

Choosing your Elixir version

The previous example will just use the current (based on the release channel you are following) version of Elixir available to you. What if you wanted to use a specific release version, or even a custom version (master, specific branch, etc)

Using a specific version

This is rather easy. In the example shell.nix file I linked, you can see that we depend on pkgs.elixir. If you needed to stay at say, Elixir 1.4, you would just use pkgs.elixir_1_4 instead. This should set you up using a specific version of Elixir instead of rolling with whichever version becomes the default.

Using a custom version

This becomes a bit more involved, but still fairly easy.

This gist describes the two files needed in order to use a custom version of Elixir. In this case, I just grabbed a recent random commit and plugged it into the file. Since we are using a non-standard version, it will need to compile Elixir, so it may take a bit of time, depending on your computer.

How does Erlang fit into this?

Right now, the default version of Erlang across all of nixpkgs is R20. This can of course be changed depending on your needs. In the case of using a specific version of Elixir, you will just need to replace pkgs.elixir with pkgs.beam.packages.erlangR21.elixir_1_4. Replace erlangR21 and elixir_1_4 with whichever versions of Erlang and Elixir you want.

To use a different version of Erlang with a custom Elixir version, just replace inherit rebar erlang with inherit rebar erlang = erlangR21, or whichever version of Erlang you want to use.

Keep in mind with the way we have nix building things, the version of Elixir that you are running, will ALWAYS be compiled with the version of Erlang you are running. So you should never run into issues with compatibility.

Wrapping up

This took a bit longer than I expected to put together, but here it is. If you want to look into nix a bit more, I will post a handful of external links to various blog articles, videos, communities, etc that will hopefully get you off the ground. Feel free to ask any questions about anything nix related. I am by no means an expert, but I will do my best to answer or find someone who can.


External links

Nixos Forums
#nixos on freenode
Using nix with Haskell (I know this is not BEAM related, but he does some really cool things that I hope we can get going with the BEAM community at some point)
Nix manual
Nixpkgs manual
Nix pills

18 Likes