How to override dependency versions when building a Haskell project with Nix

🎉 I am writing these notes at Brick, a magical mystery no-bullshit publishing platform. Turns out writing goes much faster when I don't have to hit “Publish” or do git commit.

You can use it too — check it out at Brick.do.


Use deps from Hackage

In the simplest case, you can just use callHackage:

  haskellPackages = pkgs.haskellPackages.override {
    overrides = self: super: rec {
      range-set-list = pkgs.haskell.lib.dontCheck
        (self.callHackage "range-set-list" "0.1.3" { });
      stm-containers = pkgs.haskell.lib.dontCheck
        (self.callHackage "stm-containers" "1.1.0.4" { });
    }; 
  };

⚠️ I use pkgs.haskell.lib.dontCheck to disable running tests while building the packages — usually this is what I want. Sometimes I would use pkgs.haskell.lib.dontHaddock as well.

Use deps from Hackage, but super ultra fresh

Sometimes you might get an error like: tar: */range-set-list/0.1.3/range-set-list.json: Not found in archive. This means the Hackage dump shipped with nixpkgs is not recent enough. Then, use callHackageDirect:

  haskellPackages = pkgs.haskellPackages.override {
    overrides = self: super: rec {
      range-set-list = pkgs.haskell.lib.dontCheck (
        self.callHackageDirect {
          pkg = "range-set-list";
          ver = "0.1.3";
          sha256 = pkgs.lib.fakeSha256;
        } { });
    }; 
  };

Nix will fetch the package and tell you what is the right hash to use instead of pkgs.lib.fakeSha256.

⚠️ I recommend always using pkgs.lib.fakeSha256 — if you copy and paste a hash belonging to some other dependency, Nix will just pick it up from the cache instead of telling you what the right hash is.

Use deps from GitHub / any other git repository

  haskellPackages = pkgs.haskellPackages.override {
    overrides = self: super: rec {
      proto3-wire =
        pkgs.haskell.lib.dontCheck (
          self.callCabal2nix "proto3-wire" (pkgs.fetchgit {
            url = "https://github.com/awakenetworks/proto3-wire.git";
            sha256 = pkgs.lib.fakeSha256;
            rev = "4f355bbac895d577d8a28f567ab4380f042ccc24";
            fetchSubmodules = true;
          }) { });
    };
  };

Use deps from a local directory

  haskellPackages = pkgs.haskellPackages.override {
    overrides = self: super: rec {
      some-lib = self.callCabal2nix "some-lib" ./some-lib { };
    }; 
  };

Import a .nix file from a repo

  repo = builtins.fetchGit {
      url = ...;
      rev = ...;
  };
  haskellPackages = pkgs.haskellPackages.override {
    overrides = self: super: rec {
      some-lib = self.callPackage (import "${repo}/nix/some-lib.nix") { };
    }; 
  };