Nix is a powerful package manager 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.
- The official manual
- Unofficial user wiki
- Nix Pills – an in depth introduction
Installing Nix is easy and straightforward; follow the installation instructions for macOS.
Nix is also very painless to remove because all its dependencies live in /nix
and if you remove that folder, your system will be free of Nix again. This means there is no reason not to try it.
If you have Nix you don’t really need Homebrew or similar tools anymore. Not all packages are available in Nix, but so far I haven't encountered any that I've been missing in my daily workflow.
👉 This is the most used command. Projects that have a Nix configuration can be run very easily if you have Nix installed. Just make sure that whenever you open a new terminal window and navigate to the project’s root folder, you run
nix-shell
After this you can run all the project’s commands, e.g. make
or yarn add …
and be sure that all the tools that this project needs are available.
This looks overly complex, which is why we document it here. Use this to get hold of the package name that you can then use to install or reference it.
nix-env -qaP .*iconv.*
If you just want to try out a package or need to run a command only once, start a shell with the package available:
nix-shell -p yarn
This installs yarn
globally, making it available in all terminal sessions:
nix-env -i yarn
You should update your Nix from time to time using the following commands. For projects that have a shell.nix
file to describe their environment, this is not necessary, this is only for your global packages (and the Nix binary).
nix-channel --update
nix-env -u --always
# Then, if everything works fine
nix-collect-garbage -d
We rarely want to have binaries installed globally, because that is only specific to a single machine and another team member might not have the required binaries available; this is where Nix expressions come in.
Create a shell.nix
file in your project’s root directory with the following contents:
let
pkgs = import <nixpkgs> {};
stdenv = pkgs.stdenv;
in rec {
project = stdenv.mkDerivation rec {
name = "my-node-application";
buildInputs = [
pkgs.nodejs
pkgs.yarn
];
};
}
Then, still from your project’s root directory, run
nix-shell
to get into a shell environment with all the specified dependencies available. You’re ready to work!
The above example is not entirely deterministic because different people might have different Nix channels on their machines, leading to slightly different dependencies being installed. To pin your packages to an exact version, you need to follow these steps:
Start a shell with a helper script in path
nix-shell -p nix-prefetch-scripts
Fetch the current Nix git repository’s revision and sha256 hash
nix-prefetch-git --no-deepClone --url https://github.com/NixOS/nixpkgs.git
Returns something like this:
{
"url": "https://github.com/NixOS/nixpkgs.git",
"rev": "910b5cda19d29b1bdab3c88bd0cc5bbf29520590",
"date": "2018-01-06T16:57:58+08:00",
"sha256": "1sf9chk6jsmyh3bq122fl7c75yr5dbl3c7brfw737aq1skvcgkyh",
"fetchSubmodules": true
}
Create your shell.nix
file and use the information from above
let
unpinned = import <nixpkgs> {};
in
{ pkgs ? import (unpinned.fetchFromGitHub
{ owner = "NixOS";
repo = "nixpkgs";
rev = "910b5cda19d29b1bdab3c88bd0cc5bbf29520590";
sha256 = "1sf9chk6jsmyh3bq122fl7c75yr5dbl3c7brfw737aq1skvcgkyh";
}) {}
}:
pkgs.stdenv.mkDerivation rec {
name = "example-project-with-gdal-ruby-node";
buildInputs = [
pkgs.gdal
pkgs.ruby_2_1
pkgs.bundler
pkgs.nodejs
pkgs.yarn
];
}
More info can be found on the Nix wiki about Pinning Nixpkgs.
It can be necessary to specify an older project’s dependencies as they were at the time the project was created and not as they are today. For this you can point to a specific revision of the Nix packages repo like so (note the --rev
, i.e. revision, option)
nix-prefetch-git --no-deepClone --url https://github.com/NixOS/nixpkgs.git --rev 6ed8a76ac64c88df0df3f01b536498983ad5ad23
This is an example that points to the Nix release 0.14 from 2012.
Nix can be specified as a shell interpreter so you can write shell scripts in your favourite language. Here’s an example:
#! /usr/bin/env nix-shell
#! nix-shell -i python -p python pythonPackages.prettytable
import prettytable
# Print a simple table.
t = prettytable.PrettyTable(["N", "N^2"])
for n in range(1, 10): t.add_row([n, n * n])
print t
Nix can also replace Docker: https://lethalman.blogspot.ch/2016/04/cheap-docker-images-with-nix_15.html
- You can have multiple versions of a package installed without problems
- Upgrading or uninstalling packages can’t break other packages since there is no mutation hell
- Nix helps you make sure that package dependency specifications are complete
- Atomic upgrades and rollbacks – when an upgrade breaks things, you can just
nix-env --rollback
to get back to the previous state - Packages are built from Nix expressions, which is a simple functional language. This makes building deterministic and building a Nix expression twice should yield the same result
- Nix can skip building from source and instead use a binary cache with pre-built binaries Toolchain
There are several tools in the Nix ecosystem:
- Nixpkgs – The Nix Packages collection
- NixOps – The NixOS Cloud Deployment Tool
- NixOS – The Purely Functional Linux Distribution
- nix-darwin –
/etc/nixos/configuration.nix
for macOS (experimental)
- Nix treats packages like immutable values, built by functions that don’t have side-effects
- Packages are stored in the Nix store, usually at
/nix/store
- Each package has a unique subdirectory, e.g.
/nix/store/mlhw8gn5vc8p6cqf00bp53dqkbm35kd0-nodejs-7.2.1
- To make these packages available to you, Nix references the packages in the store that belong together with symlinks
- Global packages are symlinked into
~/.nix-profile
, you add this to your path withsource ~/.nix-profile/etc/profile.d/nix.sh
- Project specific package sets can be specified with a
shell.nix
file and will be accessible if you runnix-shell
- To remove Nix from your system, you just delete
/nix
and everything is gone 💥 Caveats