---
title: Shrinking Haskell Docker images using multi-stage builds | Codurance
description: Shrinking Haskell Docker images using multi-stage builds
---

[Publications | Codurance ](https://www.codurance.com/publications)

# [Shrinking Haskell Docker images using multi-stage builds | Codurance](https://www.codurance.com/publications/2017/12/21/docker-multistage-haskell)

 Written by [Liam Griffin-Jowett](https://www.codurance.com/publications/author/liam-griffin-jowett) | 21 Dec 2017

I have recently discovered Docker's new [multi-stage build](https://docs.docker.com/engine/userguide/eng-image/multistage-build/#use-multi-stage-builds) feature. This has been a great help in answering my question of how to reduce the size of my haskell images for deploying, as the main [haskell image](https://hub.docker.com/_/haskell/) on Docker Hub is over 1GB before you start adding things. This also means you don't have to maintain two Dockerfiles.

With multi stage builds we can use the `haskell` docker image to build our distributable executable, then copy this to a smaller image (in this case `phusion/baseimage`).

Here's an example Dockerfile for a project called `haskell-example`:

```
FROM haskell as build-env
WORKDIR /opt/server
RUN cabal update
COPY haskell-example.cabal .
RUN cabal install --only-dependencies -j4
ADD . .
RUN cabal install

FROM phusion/baseimage
WORKDIR /opt/server
COPY --from=build-env /opt/server/dist .

CMD ./build/haskell-example/haskell-example
```

Before, using just the haskell image: 1.87GB.

After, using multi-stage with baseimage: 249MB.

## Image caching

There's just one problem with this method - the intermediate images are all marked as dangling. This means that if you do a `docker system prune` and rebuild, you will have install all your dependencies again, which takes a lot of time in the haskell world.

The workaround for this is to build an image using the `build-env` stage. This is done by specifying the target when building.

```
docker build -t haskell-example-dev --target build-env .
```

This keeps the image in the cache so it won't be `prune`'d.

## Next steps

So we've shrunk our deployable image using `phusion/baseimage`, can we go further? The next step would be to use something like alpine as the production image, a mere 4.14MB. That's what I'll talk about next time :)

[This post was cross-posted to my personal blog.](https://medium.com/@Gryff)

[View full post](https://www.codurance.com/publications/2017/12/21/docker-multistage-haskell)

```json
{
  "@context" : "http://schema.org",
  "@type" : "BlogPosting",
  "author" : {
    "@type" : "Person",
    "name" : "Liam Griffin-Jowett"
  },
  "dateModified" : "2021-12-02T22:51:32.588Z",
  "datePublished" : "2017-12-21T00:00:00Z",
  "headline" : "Shrinking Haskell Docker images using multi-stage builds",
  "image" : {
    "@type" : "ImageObject",
    "height" : 416,
    "url" : "https://f.hubspotusercontent10.net/hubfs/3042464/Imported_Blog_Media/2017-12-21-docker-multistage-haskell-1.jpg",
    "width" : 640
  },
  "mainEntityOfPage" : "https://www.codurance.com/publications/2017/12/21/docker-multistage-haskell",
  "publisher" : {
    "@type" : "Organization",
    "logo" : {
      "@type" : "ImageObject",
      "height" : 60,
      "url" : "/hs/hsstatic/content_shared_assets/static-1.4092/img/default-amp-logo.png",
      "width" : 60
    },
    "name" : "Publications"
  }
}
```