State of Haskell Nix ecosystem (2024)

@fricklerhandwerk I do in fact have Opinions about the whole nix haskell thing :smiley:

First of all, I think the current approach has its merits, and we should be aware of them when thinking about a replacement.

A single, globally consistent¹ package set has great value for a software distribution. Mainly, it means there is only one place where you have to perform package-specific fixes. Security fixes are especially important.

¹: Meaning that there is only one version of each package.

Only 147 packages from haskellPackages have multiple versions. Compare that to Rust, where every package can depend on many different versions of other packages… and this is what happens. Many people have written about the problem.

Haskell packages are, I think, particularly amenable to the construction of a consistent package set. This is probably because, unlike Rust, they suffer from the diamond dependency problem, that was actually embraced through Stackage.

What we are doing with Haskell packages is not possible for ecosystems like Go and Rust npm. When it is possible (in Python for example), we are generally following the Haskell approach. Consistency is —in the context of nixpkgs— a desirable property.


Now, while this may be true for nixpkgs itself, external development is another story. As you write, you might have to use a different GHC version, or a different version of a package deep in the dependency tree. In that case, I think tools like haskell.nix are a perfectly fine solution. Like callCabal2nix (which is IFD), they could even be included in nixpkgs, though I don’t really see why — they work fine as external tools for external development.

Regarding endorsement in the manual, I have no strong opinion.


But what if you still want to avoid the constraints of a globally consistent package set and IFD, for actual use in nixpkgs? I can see two options. Both are similar to the rust setup you mentioned.

  1. Checking in some kind of lockfile. This can be ­—for example— plan.json, a conversion of plan.json to nix, or something based on mitmproxy like deps.json from the new gradle builder.
    • Equivalent to buildRustPackage with cargoLock.lockFile
    • Probably wouldn’t be accepted for general use in nixpkgs due to #327064. Even if upstream tools are changed to directly generate nix-digestible lockfiles, this won’t change.
  2. Using FODs. I have implemented this at nix-build-cabal-project: Alternative Haskell Nix infrastructure based on cabal and fixed-output derivations
    • Equivalent to buildRustPackage with cargoHash
    • Like buildRustPackage, it requires you to rebuild the full dependency tree from scratch for every package.
    • I can see something like this being used in nixpkgs. Probably for a limited amount of packages (remember that this approach loses all the advantages of a consistent package set).

Finally, there will soon be a third way: RFC92 computed derivations / dynamic derivations. These will have the advantages of checked-in lockfiles… without the actual lockfiles. There is also potential for some interesting upstream integration. However computed derivations still have a long way to go before they are usable in nixpkgs.

10 Likes