In the Ad hoc developer environments tutorial we looked at providing shell environments for when we need a quick’n’dirty way of getting hold of some tools.
In this tutorial we’ll take a look how to create reproducible shell environments given a declarative configuration file called a Nix expression.
This is the quickest approach to getting started with Nix:
use single command to invoke it via nix-shell
it works across different operating systems (Linux / MacOS)
you share the exact same environment with all developers
Developer environments allow you to:
provide CLI tools, such as psql
, jq
, tmux
, etc
provide developer libraries, such as zlib
, openssl
, etc
set shell environment variables
execute bash during environment activation
At the top-level of your project create shell.nix
with the following contents:
{ pkgs ? import (fetchTarball "https://github.com/NixOS/nixpkgs/archive/3590f02e7d5760e52072c1a729ee2250b5560746.tar.gz") {} }:
pkgs.mkShell {
buildInputs = [
pkgs.which
pkgs.htop
pkgs.zlib
];
}
Note
To understand the first line, read through pinning nixpkgs tutorial.
We import nixpkgs
and make a shell with which
and htop
available in $PATH
.
zlib
provides libraries and headers in case we’re compiling something against it.
To enter the environment:
$ nix-shell
these paths will be fetched (0.07 MiB download, 0.20 MiB unpacked):
/nix/store/072a6x7rwv5f8wr6f5s1rq8nnm767cfp-htop-2.2.0
copying path '/nix/store/072a6x7rwv5f8wr6f5s1rq8nnm767cfp-htop-2.2.0' from 'https://cache.nixos.org'...
[nix-shell:~]$
The command will start downloading the missing packages from the https://cache.nixos.org binary cache.
Once it’s done, you are dropped into a new
shell. This shell provides the packages specified in shell.nix
.
Run htop
to confirm that it is present. Quit the program by hitting
q
.
Now, try which htop
to check where the htop
command is on disk.
You should see something similar to this:
[nix-shell:~]$ which htop
/nix/store/y3w2i8kfdbfj9rx287ad52rahjpgv423-htop-2.2.0/bin/htop
Given the following shell.nix
:
{ pkgs ? import (fetchTarball "https://github.com/NixOS/nixpkgs/archive/3590f02e7d5760e52072c1a729ee2250b5560746.tar.gz") {} }:
pkgs.mkShell {
buildInputs = [
pkgs.which
pkgs.htop
pkgs.zlib
];
shellHook = ''
echo hello
'';
MY_ENVIRONMENT_VARIABLE = "world";
}
Running nix-shell
we observe:
$ nix-shell
hello
[nix-shell:~]$ echo $MY_ENVIRONMENT_VARIABLE
world
The shellHook
section allows you to execute bash while entering the shell environment.
Any attributes passed to mkShell
function are available once the shell environment is active.
direnv
: Automatically activating the environment on directory changeBesides activating the environment for each project, every time you change
shell.nix
you need to re-enter the shell.
You can use direnv
to automate this process for you, with the downside that each developer needs
to install it globally.
direnv
At the top-level of your project run:
echo "use nix" > .envrc && direnv allow
The next time your launch your terminal and enter the top-level of your project direnv will check for changes.
$ cd myproject
direnv: loading myproject/.envrc
direnv: using nix
hello
Towards reproducibility: Pinning nixpkgs to see different ways to import nixpkgs
To quickly set up a Nix project read through Getting started Nix template.