As a prelude to writing up the details of how this site is generated, I realized I should write up a nix oriented workflow for node packages.

Tooling and Idea

The basic concepts are:

  • Use npm to generate a package-lock.json file
  • Use node2nix in a shell to generate a set of nix derivations
  • Enter a shell environment with the nix inputs
  • Profit

However, the nuances of this are a bit annoying at first.

Packaging Requirements

We will use the standard npm installation method at first, but since we shouldn’t keep installing and removing things, so we need a way to modify package.json without running npm and will therefore add add-dependency.

1npm install add-dependency

Setting up Node2Nix

We will first clean the directory of what we do not need.

1rm -rf default.nix node-env.nix node-packages.nix node_modules

Now we can enter a shell with node2nix and generate files for the node packages.

1nix-shell -p 'nodePackages.node2nix'
2node2nix -l package-lock.json

A Nix Environment

We will use the standard setup described in the tutorial post:

1nix-env -i niv lorri
2niv init
3niv update nixpkgs -b nixpkgs-unstable

This is to be in conjunction with the following shell.nix file 1.

1{ sources ? import ./nix/sources.nix }:
3  pkgs = import sources.nixpkgs { };
4  nodeEnv = pkgs.callPackage ./node-env.nix { };
5  nodePackages = pkgs.callPackage ./node-packages.nix {
6    globalBuildInputs = with pkgs; [ zsh ];
7    inherit nodeEnv;
8  };

Note that we have overridden the nodePackages shell which is defined in the files created by node2nix.

We can now enter the environment and setup node_modules2.

2ln -s $NODE_PATH node_modules


Unfortunately, this setup is a little fragile to updates. We will need to exit and re-create the setup. Note that we are removing the lock file now as well.

1# In the nix-shell
2add-dependencies babel-loader @babel/core @babel/preset-env core-js @babel/plugin-transform-regenerator
3# Do not run in nix-shell
4rm -rf default.nix node-env.nix node-packages.nix node_modules package-lock.json
5# Update in a line
6nix-shell -p 'nodePackages.node2nix' --run 'node2nix package.json'

The single line update mechanism can be run in the nix-shell itself, making things marginally less painful.


This has been a short introduction to working with the nix-shell ecosystem. It isn’t as fast as working with the normal setup, and it is a pretty annoying workflow. Given that most CI setups have good support for caching npm dependencies, it doesn’t seem worthwhile at the moment.

  1. There might be a better approach defined in this issue later ↩︎

  2. We can’t use lorri yet since we need to selectively add and remove the symbolic link to node_modules ↩︎