In the previous post, we learned how to get started with managing and building a Haskell project with Nix. In this post, we learn how to easily create statically-linked executables for Haskell projects with Nix.

In the previous post, we learned how to get started with managing and building a Haskell project with Nix. In this post, we learn how to easily create statically-linked executables for Haskell projects with Nix.

This post is a part of the series: Nix for Haskell.

  1. Getting Started
  2. Static Builds 👈

Contents

  1. Static Builds
  2. Enabling Static Builds in GHC
  3. Configuring the Application
  4. Rooting Static Build Dependencies
  5. Finale
  6. Bonus: Building a Docker Image
  7. Conclusion

I recommend going through the previous post, because we are going to start off from where we left last time (ignoring the bonus sections). This is how our project’s directory tree looks at this point:

.
|— app
|  |— Main.hs
|— ftr.cabal
|— nix
|  |— nixpkgs.nix
|  |— sources.json
|  |— sources.nix
|— package.nix
|— shell.nix

Main.hs is the default generated main file that prints “Hello, Haskell!”. ftr.cabal is the default generated Cabal file. sources.(json|nix) are generated by Niv to pin Nixpkgs to a particular revision. nixpkgs.nix provides the nixpkgs that we use for building tools and dependencies. package.nix and shell.nix build the package and manage the Nix shell respectively. We are not going to touch any of these files in this post. Let’s get started.

Static Builds#

A static build is an executable that is statically-linked against all the libraries it depends on. This is in contrast to a dynamically-linked executable, which contains references to the libraries it depends on, and those libraries are loaded and linked when the executable runs. While dynamic linking has its benefits, the main advantage of static linking is that the executable can be shipped by itself, without needing to ship or install dependency libraries. This makes it quite attractive for deploying backend services. You download and deploy that one binary executable file and you are done! No need to care about installing and maintaining its dependencies.

Many compilers support static builds—Go and Rust being two. Haskell compiler GHC also supports it, but not out-of-the-box. To statically link a Haskell executable, we need to configure GHC itself, and then configure the executable build as well. We also need to configure GHC to link with musl libc. That’s where Nix helps us by smoothing out the process1.

Enabling Static Builds in GHC#

As mentioned, first we need a GHC configured to do static builds. We create a nixpkgs derivation, separate from nixpkgs.nix, that contains the custom configured GHC.

{
  arch,
  ghcVersion ? (import ./nixpkgs.nix { }).haskellPackages.ghc.version,
}:
let
  getGHCWithVersion = lib: "ghc" + lib.replaceStrings [ "." ] [ "" ] ghcVersion;
  sources = import ./sources.nix;
in
import sources.nixpkgs {
  system = arch + "-linux";
  overlays = [
    ( final: prev:
      let
        compiler = getGHCWithVersion prev.lib;
        prevHPackages = prev.haskell.packages.${compiler};
      in prev.lib.attrsets.recursiveUpdate prev {
        haskell.packages.${compiler} = prevHPackages.override {
          ghc = prevHPackages.ghc.override {
            enableRelocatedStaticLibs = true;
            enableShared = false;
            enableDwarf = false;
            enableProfiledLibs = false;
            enableDocs = false;
            enableNativeBignum = true;
          };
          buildHaskellPackages = prevHPackages.buildHaskellPackages.override (old: {
            ghc = final.haskell.packages.${compiler}.ghc;
            buildHaskellPackages = final.haskell.packages.${compiler};
          });
        };
      })

    ( final: prev:
      let compiler = getGHCWithVersion prev.lib;
      in {
        haskellPackages = prev.haskell.packages.${compiler};
        ghc = prev.haskell.packages.${compiler}.ghc;
      })

    ( final: prev: {
      haskell = prev.haskell // {
        packageOverrides = prev.lib.composeExtensions prev.haskell.packageOverrides (
          hfinal: hprev: {
            mkDerivation = args:
              hprev.mkDerivation (
                args // {
                  doCheck = false;
                  doHaddock = false;
                  enableLibraryProfiling = false;
                  enableExecutableProfiling = false;
                });
          });
      };
    })
  ];
  config = { };
}
nix/nixpkgs-static-ghc.nix

Let’s go over it piece-by-piece. First, we take the arch and ghcVersion parameters, letting us build the package for different architectures (X86-64 and AArch64), and for different GHC versions. We default the ghcVersion to the default GHC in nixpkgs.

The derivation is same as nixpkgs.nix, except we add some overlays. The first overlay adds the custom configured GHC for static builds. We enable certain configurations for that purpose:

enableRelocatedStaticLibs = true Configures GHC runtime system and core packages to be built with position independent code so that they can be loaded for template Haskell. enableShared = false Disables building dynamically-linkable libraries, so they are built only as static archives. enableDwarf = false Disables DWARF-based stack traces, because it is unavailable on musl targets. enableProfiledLibs = false Disables building profiling enabled libraries. enableDocs = false Disables generation of documentation. enableNativeBignum = true Makes GHC use pure-Haskell based native bignum backend ghc-bignum instead of GMP, so that the package executables it creates are GPL-free. You may remove this setting if you are okay with GPL executables.

The buildHaskellPackages related lines set the custom GHC as the compiler for Haskell-based tools used in Nix2.

The second overlay makes cabal2nix—the tool used to convert .cabal files into Nix derivations—use the custom GHC. The third overlay disables documentation generation, testing, and profiling of all Haskell libraries built with the custom GHC. We do this to save the build time, assuming that static builds are for release only, and the docs, tests, and profiling are done using a normal GHC.

Building this custom GHC may take anywhere from several minutes to several hours depending on the build machine configuration34. But this is a one-time price to pay, as long as we keep the GHC build around. Next, we configure our package to be built as a statically-linked executable.

Configuring the Application#

The package-static.nix file is equivalent of the package.nix file from the previous post, but builds statically-linked exes.

{
  arch,
  ghcVersion ? (import ./nix/nixpkgs.nix { }).haskellPackages.ghc.version,
}:
let
  pkgsOrig = import ./nix/nixpkgs-static-ghc.nix { inherit arch ghcVersion; };
  pkgs = pkgsOrig.pkgsMusl;
  hlib = pkgs.haskell.lib.compose;

  staticDeps = import ./nix/static-deps.nix { inherit pkgs; };
  inherit (staticDeps) libffi zlib numactl;
in
pkgs.lib.pipe
  (pkgs.haskellPackages.callCabal2nix "ftr" (pkgs.lib.cleanSource ./.) { })
  [ hlib.dontHaddock
    hlib.dontHyperlinkSource
    hlib.dontCoverage
    hlib.disableExecutableProfiling
    hlib.disableLibraryProfiling
    hlib.disableSharedLibraries
    hlib.justStaticExecutables
    hlib.enableDeadCodeElimination
    ( hlib.overrideCabal (old: {
      enableParallelBuilding = true;
      buildTools = (old.buildTools or [ ]) ++ [ pkgsOrig.buildPackages.lld ];
    }))
    ( hlib.appendConfigureFlags [
      "-O2"
      "--ghc-option=-fPIC"
      "--ghc-option=-optl=-static"
      "--ghc-option=-split-sections"
      "--ghc-option=-optl-fuse-ld=lld"
      "--ld-option=-fuse-ld=lld"
      "--with-ld=ld.lld"
      "--ld-option=-Wl,--gc-sections,--build-id,--icf=all"
      "--extra-lib-dirs=${libffi}/lib"
      "--extra-lib-dirs=${zlib}/lib"
      "--extra-lib-dirs=${numactl}/lib"
    ])
    ( src: pkgs.stdenv.mkDerivation {
      name = "${src.name}-compressed";
      inherit src;
      nativeBuildInputs = [ pkgsOrig.upx ];
      installPhase = ''
        mkdir -p $out
        cp -R $src/. $out
        chmod -R +w $out/bin
        upx -q --lzma -1 $out/bin/*
        chmod -R -w $out/bin
      '';
    })
  ]
package-static.nix

Let’s go over the file in parts.

package-static.nix also takes arch and ghcVersion as parameters, and passes them to nix/nixpkgs-static-ghc.nix to create the nixpkgs with the custom GHC as described above. This give us pkgsOrig, from which we get the pkgsMusl version. pkgsMusl is same nixpkgs, except every executable in it links to musl libc. We capture this as pkgs, and use it to build our Haskell package.

When linking the executable, we need to link it against static version of all the dependency libraries it depends on. That’s what nix/static-deps.nix file provides us. We’ll look at it in the next section, but for now, we see that it gives us the libffi, zlib, and numactl libraries5.

Finally, we get to the package configuration. It starts the same as package.nix, using cabal2nix to connect the Haskell project to Nix, but then, we provide a list of custom configurations. We disable Haddock docs, hyperlinked source docs, coverage tests, profiling, and shared library build. We enable static executable build and dead code elimination. Then we configure cabal to run builds with multithreading, and add lld to its list of build tools.

Then, we add many configuration flags:

-O2 Enables optimization. --ghc-option=-fPIC Enables emission of position independent code. --ghc-option=-optl=-static Enables static linking. --ghc-option=-split-sections Enables split sections to produce smaller binaries. --ghc-option=-optl-fuse-ld=lld, --ld-option=-fuse-ld=lld, --with-ld=ld.lld Configures GHC to use lld as the linker, which is much faster than the default linker. You can omit these lines to use the default linker. Or you can replace all metions of lld with mold to use the Mold linker, which may be even faster depending on your project. --ld-option=-Wl,--gc-sections,--build-id,--icf=all Enables reductions in binary size by removing dead code6. --extra-lib-dirs=... These lines allow GHC to link the output executable against the static version of the mentioned dependency libraries.

Finally, the last function in the pipeline uses UPX to compress the output executable. This generally results in a large reduction in the binary size7.

Now we can actually build the statically-linked exe:

$ nix-build --argstr arch x86_64 package-static.nix
$ nix-build --argstr arch aarch64 package-static.nix
$ nix-build --argstr arch x86_64 --argstr ghcVersion "9.12" package-static.nix

The first and second line above build the exe for the X86-64 and AArch64 architectures with the default GHC version. The third line specifies a different GHC version to build with. Here is the cleaned-up output log for the first command:

Output log
$ nix-build --argstr arch x86_64 package-static.nix
these 2 derivations will be built:
  /nix/store/42a291bq7ydvkdy3fdsyj82axrfsi6sy-ftr-0.1.0.0.drv
  /nix/store/2c2l50la8291q0jrqlc23bybaxwip8y2-ftr-0.1.0.0-compressed.drv
building '/nix/store/42a291bq7ydvkdy3fdsyj82axrfsi6sy-ftr-0.1.0.0.drv' on 'ssh-ng://builder@linux-builder'...
copying 1 paths...
copying path '/nix/store/l9ls307kzxby72hqj4yl7ri7m8s3b3fk-source' to 'ssh-ng://builder@linux-builder'...
building '/nix/store/42a291bq7ydvkdy3fdsyj82axrfsi6sy-ftr-0.1.0.0.drv'...
Running phase: setupCompilerEnvironmentPhase
Build with /nix/store/717lxds14ra0ndbnin2qhdhh91d3b69g-ghc-musl-native-bignum-9.10.3.
Running phase: unpackPhase
unpacking source archive /nix/store/l9ls307kzxby72hqj4yl7ri7m8s3b3fk-source
source root is source
Running phase: patchPhase
Running phase: compileBuildDriverPhase
setupCompileFlags: -package-db=/nix/var/nix/b/10kwxdphxvyy519y831ryji7fn/b/tmp.EPOEKNjT6Z/setup-package.conf.d -threaded
[1 of 2] Compiling Main             ( /nix/store/4mdp8nhyfddh7bllbi7xszz7k9955n79-Setup.hs, /nix/var/nix/b/10kwxdphxvyy519y831ryji7fn/b/tmp.EPOEKNjT6Z/Main.o )
[2 of 2] Linking Setup
Running phase: updateAutotoolsGnuConfigScriptsPhase
Running phase: configurePhase
configureFlags: --verbose --prefix=/nix/store/pb2zay1k8b0vifhx7ghd5j6lbncq4b66-ftr-0.1.0.0 --libdir=$prefix/lib/$compiler/lib --libsubdir=$abi/$libname --with-gcc=gcc --package-db=/nix/var/nix/b/10kwxdphxvyy519y831ryji7fn/b/tmp.EPOEKNjT6Z/package.conf.d --ghc-option=-j4 --ghc-option=+RTS --ghc-option=-A64M --ghc-option=-RTS --disable-library-profiling --disable-profiling --disable-shared --disable-coverage --enable-static --disable-executable-dynamic --disable-tests --disable-benchmarks --enable-library-vanilla --disable-library-for-ghci --enable-split-sections --enable-library-stripping --enable-executable-stripping -O2 --ghc-option=-fPIC --ghc-option=-split-sections --ghc-option=-optl-fuse-ld=lld --ld-option=-fuse-ld=lld --ld-option=-Wl,--gc-sections,--build-id,--icf=all --with-ld=ld.lld --ghc-option=-optl=-static --extra-lib-dirs=/nix/store/yi771fg1dfj1bg618vv5flmisy8zw3hm-libffi-3.5.2/lib --extra-lib-dirs=/nix/store/jk77s356gjn68dcrzpz1m7m5amzxmkw8-zlib-1.3.2-static/lib --extra-lib-dirs=/nix/store/044b10glmg0f3yyijmrwrgv5lsys6x6n-numactl-2.0.18/lib --extra-lib-dirs=/nix/store/m1j2f9b1h6pbq1mq5ibnw4cpp60w5dfi-libffi-3.5.2/lib --extra-include-dirs=/nix/store/j9c1ifaa7vph3zxfbzb55y1frm0vp4xm-musl-iconv-1.2.5/include --extra-lib-dirs=/nix/store/lrrmafbkrpa4f3wxfz6a3sd3dv6xgp7n-numactl-2.0.18/lib

[snip]

Running phase: buildPhase
Preprocessing executable 'ftr' for ftr-0.1.0.0...
Building executable 'ftr' for ftr-0.1.0.0...
[1 of 1] Compiling Main             ( app/Main.hs, dist/build/ftr/ftr-tmp/Main.o )
[2 of 2] Linking dist/build/ftr/ftr
Running phase: haddockPhase
Running phase: installPhase
Installing executable ftr in /nix/store/pb2zay1k8b0vifhx7ghd5j6lbncq4b66-ftr-0.1.0.0/bin
Warning: The directory
/nix/store/pb2zay1k8b0vifhx7ghd5j6lbncq4b66-ftr-0.1.0.0/bin is not in the
system search path.
Running phase: fixupPhase
shrinking RPATHs of ELF executables and libraries in /nix/store/pb2zay1k8b0vifhx7ghd5j6lbncq4b66-ftr-0.1.0.0
shrinking /nix/store/pb2zay1k8b0vifhx7ghd5j6lbncq4b66-ftr-0.1.0.0/bin/ftr
patchelf: cannot find section '.dynamic'. The input file is most likely statically linked
checking for references to /nix/var/nix/b/10kwxdphxvyy519y831ryji7fn/b/ in /nix/store/pb2zay1k8b0vifhx7ghd5j6lbncq4b66-ftr-0.1.0.0...
patchelf: cannot find section '.dynamic'. The input file is most likely statically linked
patching script interpreter paths in /nix/store/pb2zay1k8b0vifhx7ghd5j6lbncq4b66-ftr-0.1.0.0
stripping (with command strip and flags -S -p) in  /nix/store/pb2zay1k8b0vifhx7ghd5j6lbncq4b66-ftr-0.1.0.0/bin
copying 1 paths...
copying path '/nix/store/pb2zay1k8b0vifhx7ghd5j6lbncq4b66-ftr-0.1.0.0' from 'ssh-ng://builder@linux-builder'...
building '/nix/store/2c2l50la8291q0jrqlc23bybaxwip8y2-ftr-0.1.0.0-compressed.drv' on 'ssh-ng://builder@linux-builder'...
copying 0 paths...
building '/nix/store/2c2l50la8291q0jrqlc23bybaxwip8y2-ftr-0.1.0.0-compressed.drv'...
Running phase: unpackPhase
unpacking source archive /nix/store/pb2zay1k8b0vifhx7ghd5j6lbncq4b66-ftr-0.1.0.0
source root is ftr-0.1.0.0
Running phase: patchPhase
Running phase: updateAutotoolsGnuConfigScriptsPhase
Running phase: configurePhase
no configure script, doing nothing
Running phase: buildPhase
no Makefile or custom buildPhase, doing nothing
Running phase: installPhase
                       Ultimate Packer for eXecutables
                          Copyright (C) 1996 - 2026
UPX 5.1.1       Markus Oberhumer, Laszlo Molnar & John Reiser    Mar 5th 2026

        File size         Ratio      Format      Name
   --------------------   ------   -----------   -----------
   1356096 ->    525804   38.77%   linux/amd64   ftr                           bin/ftr [linux/amd64, LZMA/1]

Packed 1 file.
Running phase: fixupPhase
shrinking RPATHs of ELF executables and libraries in /nix/store/j8gg1x3vrlb5dc1mh149ys0nih9fvmwk-ftr-0.1.0.0-compressed
shrinking /nix/store/j8gg1x3vrlb5dc1mh149ys0nih9fvmwk-ftr-0.1.0.0-compressed/bin/ftr
patchelf: no section headers. The input file is probably a statically linked, self-decompressing binary
checking for references to /nix/var/nix/b/19b7g2frvcvani3cnj61lsb4fq/b/ in /nix/store/j8gg1x3vrlb5dc1mh149ys0nih9fvmwk-ftr-0.1.0.0-compressed...
patchelf: no section headers. The input file is probably a statically linked, self-decompressing binary
patching script interpreter paths in /nix/store/j8gg1x3vrlb5dc1mh149ys0nih9fvmwk-ftr-0.1.0.0-compressed
stripping (with command strip and flags -S -p) in  /nix/store/j8gg1x3vrlb5dc1mh149ys0nih9fvmwk-ftr-0.1.0.0-compressed/bin
copying 1 paths...
copying path '/nix/store/j8gg1x3vrlb5dc1mh149ys0nih9fvmwk-ftr-0.1.0.0-compressed' from 'ssh-ng://builder@linux-builder'...
/nix/store/j8gg1x3vrlb5dc1mh149ys0nih9fvmwk-ftr-0.1.0.0-compressed

The output log mentions:

patchelf: cannot find section ‘.dynamic’. The input file is most likely statically linked

We can also verify for ourselves:

$ file /nix/store/j8gg1x3vrlb5dc1mh149ys0nih9fvmwk-ftr-0.1.0.0-compressed/bin/ftr
/nix/store/j8gg1x3vrlb5dc1mh149ys0nih9fvmwk-ftr-0.1.0.0-compressed/bin/ftr: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), BuildID[sha1]=df53df80d301b4bba2a7634a4169c6291d64ea72, statically linked, no section header

There is one last thing to take care of.

Rooting Static Build Dependencies#

Dynamically-linked Haskell builds contain references to their dependency libraries and GHC that was used to build it. If you use direnv or install a dynamically-linked executable, it creates Nix GC roots for the libraries and GHC, preventing them from being garbage-collected by Nix. But statically-linked builds have no references to anything, as intended. So we need to create GC roots by ourselves to the libraries and the GHC toolchain. This is even more important because building the custom GHC may be an extremely time-consuming affair.

First, we list all dependencies in a separate file:

{ pkgs }:
{
  ghc = pkgs.haskellPackages.ghc;
  jailbreak-cabal = pkgs.haskellPackages.buildHaskellPackages.jailbreak-cabal;
  cabal2nix-unwrapped = pkgs.cabal2nix-unwrapped;
  gmp6 = pkgs.gmp6.override { withStatic = true; };
  libffi = pkgs.libffi.overrideAttrs (old: { dontDisableStatic = true; });
  ncurses = pkgs.ncurses.override { enableStatic = true; };
  zlib = pkgs.zlib.static;
  numactl = pkgs.numactl.overrideAttrs (oldAttrs: {
    configureFlags = (oldAttrs.configureFlags or [ ]) ++ [
      "--enable-static"
      "--disable-shared"
    ];
  });
}
nix/static-deps.nix

This file lists the dependency libraries and the GHC toolchain. Notice how we override each library’s config to make it statically-linkable. I’ve included some additional libraries here (gmp6 and ncurses) that are generally used by Haskell projects, but we don’t use them in this project. You may have to add more of such libraries depending on your project’s dependencies.

We already saw how we use this file in package-static.nix. Now, we use it to create Nix GC roots:

{
  arch,
  ghcVersion ? (import ./nix/nixpkgs.nix { }).haskellPackages.ghc.version,
}:
let
  pkgsOrig = import ./nix/nixpkgs-static-ghc.nix { inherit arch ghcVersion; };
  pkgs = pkgsOrig.pkgsMusl;
in pkgs.symlinkJoin {
  name = "static-deps";
  paths = builtins.attrValues (import ./nix/static-deps.nix { inherit pkgs; });
}
package-static-deps.nix

package-static-deps.nix simply gathers all dependencies from nix/static-deps.nix and creates a directory with symlinks to them. This brings us to the finale.

Finale#

We create a bash script build-static.sh that builds the statically-linked executable, and creates Nix GC roots for all dependencies and the toolchain:

#!/usr/bin/env bash
set -euo pipefail

nix-build --argstr arch "$1" package-static.nix
nix-store --add-root ".gcroots/static-deps-$1" \
  --realise $(nix-instantiate --argstr arch "$1" --quiet package-static-deps.nix) \
  > /dev/null
build-static.sh

The root is created at .gcroots/static-deps-x86_64 for X86-64 architecture, for example. You can use nix-tree to explore it.

This concludes our short tutorial on how to build statically-linked executables for Haskell projects with Nix.

Bonus: Building a Docker Image#

One more thing static builds are great for: wrapping them into Docker images. Since they are much smaller than dynamically-linked executables and their dependencies combined, they are better to package as Docker images. Here’s how we do it:

{ arch }:
let
  pkgs = import ./nix/nixpkgs.nix { system = arch + "-linux"; };
  ftr = import ./package-static.nix { inherit arch; };
in
pkgs.dockerTools.buildLayeredImage {
  name = "ftr";
  tag = "latest";
  contents = [ pkgs.dockerTools.caCertificates ftr ];

  extraCommands = ''
    mkdir -p var/lib/ftr var/cache/ftr etc/ftr
    echo 'ftr:x:1000:1000::/var/lib/ftr:/sbin/nologin' > etc/passwd
    echo 'ftr:x:1000:' > etc/group
  '';
  fakeRootCommands = ''
    chown -R 1000:1000 var/lib/ftr var/cache/ftr
  '';
  enableFakechroot = true;

  config = {
    User = "1000:1000";
    Cmd = [ "/bin/ftr" ];
    Volumes = {
      "/var/lib/ftr" = { };
      "/var/cache/ftr" = { };
      "/etc/ftr" = { };
    };
  };
}
docker.nix

This image also shows how to package extra Nix packages in images, setting up a non-root user to run the executable, and setting up user-owned directories to expose as volumes. We can build the image by running:

$ nix-build --argstr arch x86_64 docker.nix
[snip]
/nix/store/cdghjrgdcf7vm0jbgjl5556zx3j4zjj1-ftr.tar.gz

Then we can load and run the image on Docker like so:

$ docker load -i /nix/store/cdghjrgdcf7vm0jbgjl5556zx3j4zjj1-ftr.tar.gz

Conclusion#

This post shows how to configure GHC and Haskell projects to build statically-linked executables that are fully portable and independent. If your Haskell project has any complex requirements, such as custom dependency versions, patched dependencies, custom non-Haskell dependencies etc., this setup may not scale. In such case you can either grow this setup by learning Nix in more depth with the help of the official Haskell with Nix docs and this great tutorial, or switch to using a framework like haskell.nix or haskell-flake. For dealing with complex static builds, static-haskell-nix project may be of help.

If you have any questions or comments, please leave a comment below. If you liked this post, please share it. Thanks for reading!


  1. I have tested this setup for GHC 9.10+ and X86-64 and AArch64 architectures only.↩︎

  2. Without this config, Nix will build a separate GHC for building Haskell-based tools used in Nix.↩︎

  3. You may need a remote Nix Linux builder to build GHC and your package if you are not on Linux or not on the right architecture. You may set up a remote builder or Linux builder on macOS.↩︎

  4. Building GHC is memory intensive. You may require few GBs of RAM.↩︎

  5. Some of your project’s dependency libraries may link to GMP directly. In such cases, the libraries provide Cabal flags to remove GMP dependency. If you don’t want GMP linked to your executable, you’ll need to override the Nix derivation for such libraries to pass those Cabal flags.↩︎

  6. I learned about using these flags from the post “Linking Smaller Haskell Binaries”. It mentions few mores tricks that may be useful to you.↩︎

  7. Note that we get the tools lld and upx from pkgsOrig, the original nixpkgs, not the musl one. We don’t need musl version of these tools for them to work, and doing that would simply cause our builds to take longer.↩︎

This post is a part of the series: Nix for Haskell.

  1. Getting Started
  2. Static Builds 👈

Like, repost, or comment

Send a Webmention for this post

Posted by Abhinav Sarkar at https://abhinavsarkar.net/posts/nix-for-haskell-static-builds/

Like this post? Subscribe to get future posts by email.