Skip to content
AgileLogics
7 min read

Haskell in Production

Prerequisites: Cabal and Stack projects

This lesson collects the practices teams use to build, ship, and run Haskell software.

Build settings

common shared
    default-language: GHC2021
    ghc-options:      -Wall -Wcompat -Wincomplete-record-updates
                      -Wredundant-constraints -Wmissing-deriving-strategies

executable server
    import:      shared
    ghc-options: -O2 -threaded -rtsopts "-with-rtsopts=-N -T"
  • Treat warnings as errors in CI (--ghc-options=-Werror), but not in local development.
  • -threaded and -N let the runtime use all cores; -T makes runtime statistics available to metrics libraries.
  • Pin dependencies with cabal freeze or a Stackage snapshot, and commit the freeze file so every build uses the same versions.

Shipping

  • A compiled Haskell program is a single native executable — copy it to the server, no runtime to install. cabal list-bin server prints where it was built.
  • Docker: build in a large image with GHC, then copy the binary into a small runtime image (multi-stage build). Fully static Linux binaries can be built with GHC on Alpine (musl) and --enable-executable-static.
  • Nix is popular in the Haskell community for fully reproducible builds and development environments.

Guarding against the unexpected

import System.Timeout (timeout)
import Control.Exception
import Text.Read (readMaybe)

slowComputation :: IO Integer
slowComputation = evaluate (sum [1 ..])

main :: IO ()
main = do
  r1 <- timeout 100000 (evaluate (sum [1 .. 1000 :: Integer]))
  print r1
  r2 <- timeout 100000 slowComputation
  print r2
  print (readMaybe "12; DROP TABLE users" :: Maybe Int)
  r3 <- try (evaluate (1 `div` (0 :: Int))) :: IO (Either ArithException Int)
  print r3
Just 500500
Nothing
Nothing
Left divide by zero
  • timeout microseconds action returns Nothing if the action takes too long — even the infinite sum [1 ..] is interrupted safely.
  • Parse untrusted input into precise types (readMaybe, aeson, a parser) and reject everything else.
  • Catch exceptions at the boundary of each request or job, log them, and keep serving — async, Warp, and most job libraries do this for you.
  • Limit memory with +RTS -M512m so a runaway computation fails cleanly instead of taking down the machine.

Code quality tools

  • HLint for suggestions, Ormolu/Fourmolu for formatting — both usually run in CI.
  • weeder finds unused code; stan does static analysis for common pitfalls such as partial functions.
  • HLS in every developer's editor.
  • cabal outdated lists dependencies with newer versions.

Where Haskell is used

Haskell's strengths — correctness, refactoring safety, concurrency, and expressive types — make it popular for compilers and developer tools (Pandoc, ShellCheck, the Elm compiler), financial systems and trading, blockchain (Cardano), back-end APIs, and anywhere complex business rules must be modeled precisely.

What's next

You've completed the course. Try the Advanced Projects — an interpreter, a JSON API, and a concurrent crawler — and then read What You Should Know Now — and What's Next for where to go from here.