Title: How to pin a nix-shell environment using niv | |
Author: Solène | |
Date: 12 January 2022 | |
Tags: nix nixos shell | |
Description: I'll explain how to use niv to pin the nixpkgs version | |
used for a nix-shell environment per project. | |
# Introduction | |
In the past I shared a bit about Nix nix-shell tool, allowing to have a | |
"temporary" environment with a specific set of tools available. I'm | |
using it on my blog to get all the dependencies required to rebuild it | |
without having to remember what programs to install. | |
But while this method was practical, as I'm running NixOS development | |
version (called unstable channel), I have to download the new versions | |
of the dependencies every time I use the nix shell. This is long on my | |
DSL line, and also a waste of bandwidth. | |
There is a way to pin the version of the packages, so I always use the | |
exact same environment, whatever the version of my nix. | |
# Use niv tool | |
Let's introduce you to niv, a program to manage nix dependencies, for | |
this how-to I will only use a fraction of its features. We just want | |
it to init a directory with a default configuration pinning the nixpkgs | |
repository to a branch / commit ID, and we will tell the shell to use | |
this version. | |
niv project GitHub homepage | |
Let's start by running niv (you can get niv from nix package manager) | |
in your directory: | |
```shell command | |
niv init | |
``` | |
It will create a nix/ directory with two files: sources.json and | |
sources.nix, looking at the content is not fascinating here (you can | |
take a look if you are curious though). The default is to use the | |
latest nixpkgs release. | |
# Create a shell.nix file | |
My previous shell.nix file looked like this: | |
```shell.nix file content | |
with (import <nixpkgs> {}); | |
mkShell { | |
buildInputs = [ | |
gnumake sbcl multimarkdown python3Full emacs-nox toot nawk mandoc libxm… | |
]; | |
} | |
``` | |
Yes, I need all of this for my blog to work because I have texts in | |
org-mode/markdown/mandoc/gemtext/custom. The blog also requires toot | |
(for mastodon), sbcl (for the generator), make (for building and | |
publishing). | |
Now, I will make a few changes to use the nix/sources.nix file to tell | |
it where to get the nixpkgs information, instead of <nixpkgs> which is | |
the system global. | |
```shell.nix file content | |
let | |
sources = import ./nix/sources.nix; | |
pkgs = import sources.nixpkgs {}; | |
in | |
with pkgs; | |
pkgs.mkShell { | |
buildInputs = [ | |
gnumake sbcl multimarkdown python3Full emacs-nox | |
toot nawk mandoc libxml2 | |
]; | |
} | |
``` | |
That's all! Now, when I run nix-shell in the directory, I always get | |
the exact same shell and set of packages every day. | |
# How to update? | |
Because it's important to update from time to time, you can easily | |
manage this using niv, it will bump the latest commit id of the branch | |
of the nixpkgs repository: | |
```shell command | |
niv update nixpkgs -b master | |
``` | |
When a new release is out, you can switch to the new branch using: | |
```shell command | |
niv modify nixpkgs -a branch=release-21.11 | |
``` | |
# Using niv with configuration.nix | |
It's possible to use niv to pin the git revision you want to use to | |
build your system, it's very practical for many reasons like following | |
the development version on multiple machines with the exact same | |
revision. The snippet to use sources.nix for rebuilding the system is | |
a bit different. | |
Replace "{ pkgs, config, ... }:" with: | |
```configuration.nix code | |
{ | |
sources ? import ./nix/sources.nix, | |
pkgs ? import sources.nixpkgs {}, | |
config, ... | |
}: | |
``` | |
Of course, you need to run "niv init" in /etc/nixos/ before if you want | |
to manage your system with niv. | |
# Extra tip: automatically run nix-shell with direnv | |
It's particularly comfortable to have your shell to automatically load | |
the environment when you cd into a project requiring a nix-shell, this | |
is doable with the direnv program. | |
nixos documentation about direnv usage | |
direnv project homepage | |
This can be done in 3 steps after you installed direnv in your profile: | |
1. create a file .envrc in the directory with the content "use nix" | |
(without double quotes of course) | |
2. execute "direnv allow" | |
3. create the hook in your shell, so it knows how to do with direnv (do | |
this only once) | |
How to hook direnv in your shell | |
Everytime you will cd into the directory, nix-shell will be | |
automatically started. |