Chris Martin

Introduction to Nix (for users of Stack)

Install Nix

curl https://nixos.org/nix/install | sh
source ~/.nix-profile/etc/profile.d/nix.sh

It can live happily in any Linux system.

Nix is like Stack

Think of Nix like Stack, but with a much broader scope.

Stack is there to manage your project’s dependencies, and help you run their programs and compile stuff with them, but only if the dependencies are Haskell packages.

Nix dependencies can be… kinda any software at all.

Nix and Stack work together nicely. When you enable Nix integration for Stack, you can add any software as a dependency of your Stack project.

So if you want to, for example, add a SASS compilation step to your Hakyll project, your coworkers don’t have to do any work to get the SASS compiler. Stack will just install it for them.

Like Stack keeps a cache of all the stuff it has installed in ~/.stack in your home directory, Nix keeps all of its stuff in /nix/store. (It’s not in your home directory, but at the root of the filesystem — for technical reasons — which is why you are prompted to sudo when you install it.)

nix-shell is like stack exec

Another comparison between Stack and Nix: You know how you can use Stack (outside the context of any project) to run executables from Haskell packages?

> stack exec --package pandoc -- pandoc --version
pandoc 1.19.2.1

nix-shell is like stack exec.

So take for example… Let’s assume you don’t have NPM installed. And let’s say you don’t really want to install it permanently or whatever because you’re probably not going to need it again, but you just want to run it for some one-off command.

> nix-shell -p nodePackages.npm --run 'npm --version'
4.1.1

-p npm is like --package pandoc; it tells Nix what packages you want available in the sandbox you’re going to run a command in. And then npm --version is the command you want to run. So that’ll download NPM and run npm --version, without actually “installing” NPM — without modifying your system visibly at all.

shell.nix is like stack.yaml

So then, also like Stack, you can use it in a sort of standalone manner like that, or you can have a config file for a project. Here’s one I’m using right now:

{ pkgs ? import <nixpkgs> {}, ghc ? pkgs.ghc }:

pkgs.haskell.lib.buildStackProject {
  name = "joyofhaskell.com";
  inherit ghc;
  buildInputs = with pkgs; [ sassc zlib ];
  LANG = "en_US.UTF-8";
  TMPDIR = "/tmp";
}

This file is called shell.nix and it sits in the root of a Hakyll project repository alongside stack.yaml.

The most important line here is the one with our dependencies:

buildInputs = with pkgs; [ sassc zlib ];

And then at the end of our stack.yaml is

nix:
  enable: true
  pure: true
  shell-file: shell.nix

which tells Stack to do everything that it does in the context of that Nix configuration, which it does by using nix-shell under the hood.

nix-env is like apt-get

You can also use Nix as an alternative to Ubuntu’s package manager (apt-get) for a lot of things if you so choose. (I’m assuming you’re using Ubuntu.)

For this we use another command, nix-env.

The basic usage of nix-env is:

  • nix-env -i npm — to install (e.g. NPM)
  • nix-env -e npm — to uninstall
  • nix-env -q — to list which package you have installed

You have no pressing need to use nix-env instead of your existing package manager at the moment, but it will be important if you ever use NixOS.

An interesting difference between nix-env and apt-get is that it only affects your user, which is why you don’t have to sudo to run it.

I write about Haskell and related topics; you can find my works online on Type Classes and in print from The Joy of Haskell.