A straight-to-the-point guide to Stack, popular Haskell build tool from FPComplete.

Also see the official guide.

edit description
or press Ctrl+Enter to savemarkdown supported
#
Building a project
other
move item up move item down edit item info delete item
Summary edit summary
# Build for development (no optimizations; compiles tests but doesn't run them)
stack build --fast --test --no-run-tests

# Build for production (-O -Wall -Werror)
stack build --pedantic

# Build a single subproject
stack build <exe/lib name>
# Build and copy binaries into ~/.local/bin
stack install

# ...or into a directory
stack install --local-bin-path=<dir>

stack build builds the project. Most common flags that you'll need:

  • --test, --bench – compile and run tests/benchmarks.

  • --no-run-tests, --no-run-benchmarks – don't run tests/benchmarks.

  • --fast – compile without optimizations.

  • --file-watch – automatically rebuild when you change files in the project. Very useful if you're not using ghcid.

  • --pedantic – compile with all warnings enabled, treating warnings as errors.

  • --profile – build with profiling.

  • --ghc-options="..." – pass extra options to GHC.

Summary quit editing summary
#
Converting an existing project to Stack
other
move item up move item down edit item info delete item
Summary edit summary
# Create a stack.yaml file
stack init --resolver=lts-XX.YY

# Create a stack.yaml file and try to guess what snapshot to use
stack init

# Use cabal-install as a project creation wizard
mkdir <project name> && cd "$_" && cabal init && stack init

stack init creates a stack.yaml file for a project with an existing .cabal file.

It's best to use as few different resolvers as possible to save space on your hard drive. Pick a snapshot you like and then pass it with --resolver=lts-XX.YY. Existing snapshots and GHC versions are cached in ~/.stack.

Summary quit editing summary
#
Running executables
other
move item up move item down edit item info delete item
Summary edit summary
# Run an executable built with 'stack build'
stack exec <executable name>

# Run an executable and pass arguments to it
stack exec -- <executable name> <arguments...>
# Run something (e.g. GHC) from a particular snapshot
stack exec --resolver=lts-12.10 -- ghc --version

# Run something from a particular GHC version distributive
stack exec --resolver=ghc-8.6.3 -- ghc --version

stack exec runs an executable in the context of the current project. It can be something built as a part of your project, but can also be a tool like ghc, cabal, haddock, or ghc-pkg.

# Build it, then run an executable
stack run <executable name> <arguments...>

# Build it, then run the first specified executable of the package
stack run

In the latest release, you can also use the new stack run command to build the package and then run the specified executable. If your package contains an executable, you can just use plain stack run to build and run this executable.

Summary quit editing summary
#
Loading the project into REPL
other
move item up move item down edit item info delete item
Summary edit summary
# Load everything
stack repl

# Load a single target (library, testsuite, etc; get the list of targets 
# with 'stack ide targets')
stack repl <target>

# Load a single module
stack repl --no-load
> :l <module name>
Summary quit editing summary
#
Creating a project from a template
other
move item up move item down edit item info delete item
Summary edit summary
# Create a directory and a project
stack new <project name> <template name> --resolver=lts-XX.YY

# Create a directory and a project, using the newest snapshot
stack new <project name> <template name>

# Create a project in the current directory
stack new <project name> <template name> --bare

stack new creates a directory and populates it with a template from GitHub. Some templates: commercialhaskell/stack-templates.

If you don't know what template to use, try simple-hpack – it creates a BSD-3 licensed executable with a package.yaml file.

It's best to use as few different resolvers as possible to save space on your hard drive. Pick a snapshot you like and then pass it with --resolver=lts-XX.YY. Existing snapshots and GHC versions are cached in ~/.stack.

Summary quit editing summary
#
Adding dependencies
other
move item up move item down edit item info delete item
Summary edit summary

To use a dependency that is available in the snapshot, add it to your .cabal or package.yaml file. Snapshot contents, including the exact package versions, are listed at https://www.stackage.org/lts-XX.YY.

library                -- In a .cabal file
  build-depends:
    aeson       
library:                # In a package.yaml file
  dependencies:
    - aeson

To use a dependency that is not in the snapshot, you also need to add it to extra-deps in stack.yaml:

extra-deps:
  # From Hackage
  - amazonka-core-1.6.0

  # From a Git / Mercurial repo (add "subdirs" if you want only certain
  # directories from the repo):
  - git: https://github.com/brendanhay/amazonka
    commit: 9750d3d0bf4a079831c20efeb9ef372759895b48
    subdirs: 
    - core

  # From a directory
  - ./amazonka/core

  # From an archive accessible by a URL (add "subdirs" if you want only
  # certain directories from the archive):
  - archive: https://github.com/brendanhay/amazonka/archive/1.6.0.tar.gz
    subdirs:
    - core

(Note: if a package isn't on Stackage, you can add it there, though it works better when you're the actual package maintainer for that package.)

Summary quit editing summary
#
Running tests
other
move item up move item down edit item info delete item
Summary edit summary
# Run all tests
stack test --fast

# Run only certain tests (hspec)
stack test --fast --ta="-m <test name pattern>"

# Run only certain tests (tasty)
stack test --fast --ta="-p <test name pattern>"

It's also possible to pass any other arguments to the testsuite with --ta. Try --ta=--help to see what arguments are supported by the test framework you're using.

Summary quit editing summary
#
Troubleshooting
other
move item up move item down edit item info delete item
Summary edit summary

If you suspect that an executable is not being rebuilt, or if something is wrong with dependency versions, etc:

# Remove build artifacts for all packages in the project
stack clean

# Remove build artifacts for a specific package
stack clean <package>

# Remove build artifacts and everything from .stack-work
stack clean --full

If a dependency is broken and you're getting weird creepy errors you haven't ever seen before:

# Remove a package from the local package database
stack exec -- ghc-pkg unregister <package>

If you're really, truly desperate and you've tried everything else (including setting your hair on fire):

# An exciting journey of rebuilding hundreds of packages awaits you
rm -rf ~/.stack
Summary quit editing summary
#
Listing dependencies
other
move item up move item down edit item info delete item
Summary edit summary
# List all dependencies, transitively
stack ls dependencies

# List test/bench dependencies too
stack ls dependencies --test --bench

# List licenses of all dependencies (useful for detecting scary GPL)
stack ls dependencies --license
# List all dependency pairs (useful for figuring out what brings
# a particular dependency in)
stack dot --external
Summary quit editing summary
#
Building documentation
other
move item up move item down edit item info delete item
Summary edit summary
# Build documentation
stack haddock --no-haddock-deps

# Build documentation for all dependencies, too (might take a long time
# if they all need to be recompiled)
stack haddock

# Open generated docs in a browser
stack haddock --open
# Start a custom Hoogle server that knows all your local packages.
# Great for looking up documentation while offline. Server is located
# at http://localhost:8080/
stack hoogle -- serve -p 8080 --local
Summary quit editing summary
#
Nix integration
other
move item up move item down edit item info delete item
Summary edit summary

Nix package manager can be used to install GHC and packages. Normally, this can speed up the compilation of packages and avoids duplicate installations of identical packages. To enable nix support, add to your stack.yaml:

nix:
  enable: true

However, this is generally not suggested, because this will automatically use nix on systems that might not have it installed, thus, the build fails. It is better to add the above lines to your yaml config template: ~/.stack/config.yaml.

Nix automatically handles system library dependencies. Such dependencies can be added by modifying your local stack.yaml, for example, if you require zlib, you do:

nix:
  packages:
  - zlib

This will allow you to build projects without modifying your global system.

Summary quit editing summary
#
Docker integration
other
move item up move item down edit item info delete item
Summary edit summary
# stack.yaml

docker:
  enable: true
# Download the image
stack docker pull

# And then build as usual!
stack build --fast

Stack can automatically download a Docker image with GHC and snapshot libraries installed, and build your project inside of it.

TODO: docs say "FP Complete provides images for use with stack that include GHC, tools, and optionally have all of the Stackage LTS packages pre-installed in the global package database", but the image chosen by Stack doesn't have any LTS packages pre-installed. How come?

Summary quit editing summary
#
Running without stack.yaml
other
move item up move item down edit item info delete item
Summary edit summary

When there's no stack.yaml in the current directory or up the path, the global project will be used.

stack install installs a library/executable into the global project, and stack repl can access everything in the global project.

Global project settings can be changed:

# ~/.stack/global-project/stack.yaml

packages: []
resolver: lts-12.10
Summary quit editing summary