Alternative Haskell Nix infrastructure based on cabal and fixed-output derivations

877a084 Set -j $NIX_BUILD_CORES

5 months ago

c2baa4f Add contributing section

10 months ago

#nix-build-cabal-project (aka buildCabalProject)

Alternative Haskell Nix infrastructure based on cabal and fixed-output derivations

Like buildRustPackage and buildGoModule, but for Haskell!


First of all, add a freeze file to your cabal project (cabal freeze). The minimal structure for a buildCabalProject-based project is the following:

import /path/to/nix-build-cabal-project {} {
  pname = "example";
  version = "";
  src = ./example;

This will build all the executables in the example project. To choose which executables to build, you can pass a list of string as target parameter.

#Obtaning a development environment

While nix-build-cabal-project is mainly intended for deployment, it is possible to make cabal use the dependencies built by nix.

  1. Build the cabalStore attribute of your package
  2. When calling cabal, use either:
    • --store-dir result, more robust but less flexible (you'll have a read-only store!).
    • --package-db result/ghc-*/package.db, more flexible but less robust (there's a note in default.nix if you want the gory details). If it works, you should prefer this.
  3. If you change the cabal or freeze files, repeat step 1.

TODO: provide a wrapped ghc and cabal that always use the cached store

#When do I have to change the hash?

You will receive an alert if you need to update the hash.

This will happen when there are changes to the freeze file or to the targets.

If you use a solver-based build, the hash will also change when one of the following changes:

  • ghc version
  • cabal version
  • OS or architecture
  • indexState
  • .cabal and cabal.project files

For this reason, it's recommended to pin the ghc and possibly cabal version.

#Solver-based builds (no freeze file)

Projects without freeze files can also be built, since cabal's solver is deterministic. Simply pass an indexState attribute (eg. indexState = "2021-03-08T20:01:13Z";) and delete any existing freeze files, and cabal will do the dependency resolution.

#Non-Haskell dependencies

Non-Haskell dependencies (eg. zlib, pkg-config) can simply be added to buildInputs and nativeBuildInputs

#Building specific targets

You can build specific cabal targets by passing the targets attribute, eg. targets = [ "myexe1" "myexe2" ];.

#Running tests

Use doCheck as usual. You can pass a list of strings as test parameter to choose which tests to run.


You can send patches to my public-inbox mailing list or to any of the contacts listed at fgaz.me/about. Or you can send a pull request to the Codeberg mirror.

Issues are tracked at https://todo.sr.ht/~fgaz/nix-build-cabal-project

#Alternatives & comparison

There are other projects with similar objectives, and this one may not be the best for your needs. For example, it is not suitable if you need to cache dependencies individually. On the other hand, it works well if you want a simple FOD-based build like nixpkgs.rustPlatform.buildRustPackage. Here is a comparison with other projects:

  • nixpkgs.haskellPackages is the Haskell infrastructure used in nixpkgs.
    • Multi-package projects require some boilerplate.
    • It provides a fixed set of package versions based on Stackage LTS. To use other packages, you have to write/generate nix expressions for those.
    • Packages are individually cached.
    • Does not use IFD (Import From Derivation) unless you use callCabal2nix.
    • You have to commit generated files unless you use callCabal2nix.
  • haskell.nix is IOHK's Haskell infrastructure.
    • It is very flexible and can build most cabal projects out of the box.
    • It automatically produces expressions for all of hackage and more.
    • Packages are individually cached.
    • Uses IFD unless you use plan-to-nix manually.
    • There are no generated files to commit unless you use plan-to-nix manually.
    • Depends on IOHK infrastructure.
  • This project:
    • Based on Fixed Output Derivations.
    • Supports most multi-package cabal projects, but does not yet support some features such as source repository packages.
    • All of hackage can be used without boilerplate or code generation.
    • Does not cache individual dependencies.
    • Does not use IFD.
    • There are no generated files to commit.
    • Does not depend on infrastructure outside of nixpkgs and Hackage.