Build Tools, Packaging and Deployment

52.1 cabal vs Stack

Hackage (with solver) Stackage snapshots (curated sets of compatible versions) cabal freeze, index-state Snapshot resolver in stack.yaml .cabal, cabal.project

stack.yaml + .cabal or package.yaml (hpack) Libraries, modern default Applications wanting curated sets

Nix (haskell.nix, nixpkgs) gives fully reproducible builds and is popular in industry. Bazel (rules_haskell) suits large monorepos.

52.2 Publishing and Documentation

Follow the Package Versioning Policy (PVP): A.B.C.D, where A.B is the major version (breaking changes).

cabal check                        # validate the package metadata
cabal sdist                        # create a source tarball
cabal upload --publish dist-newstyle/sdist/my-lib-0.1.0.0.tar.gz   # to Hackage
cabal haddock --haddock-for-hackage && cabal upload -d --publish ...

52.3 Deployment

Static binaries: build with --enable-executable-static on musl (Alpine) or via Nix (pkgsStatic).

CI: GitHub Actions with haskell-actions/setup, cache ~/.cabal/store and dist-newstyle, run cabal build all, cabal test all, HLint, and the formatter check. haskell-ci generates CI configs for multiple GHC versions.

# Multi-stage Docker build
FROM haskell:9.6 AS build
WORKDIR /app
COPY *.cabal cabal.project* ./
RUN cabal update && cabal build --only-dependencies
COPY . .
RUN cabal install --installdir=/app/bin --install-method=copy exe:my-app

FROM debian:bookworm-slim
RUN apt-get update && apt-get install -y libgmp10 ca-certificates && rm -rf /var/lib/apt/lists/*
COPY --from=build /app/bin/my-app /usr/local/bin/my-app
EXPOSE 8080
CMD ["my-app", "+RTS", "-N", "-A64m", "-RTS"]