NoVPS
PricingBlog
Sign InSign Up
Community

Optimizing Docker Images with Multi-Stage Builds

Travis Reeder

Thu, Aug 29, 2024

Main picture

Previously, We’ve discussed creating small Docker images, but now with Docker’s support for multi-stage builds, it’s worth revisiting the topic. Previously, we had to build the binary in one step and then create the Docker image in a separate step, which could be cumbersome and tricky. Let's see if multi-stage builds simplify the process.

Note: This requires Docker 17.05 or newer.

Let's start with a basic Go program:

package main import "fmt" func main() { fmt.Println("Hello world!") }

Here's how we can build it using a single-stage Docker build with the golang:alpine image. The Dockerfile looks like this:

FROM golang:alpine WORKDIR /app ADD . /app RUN cd /app && go build -o goapp ENTRYPOINT ./goapp

Build and run the Docker image:

docker build -t treeder/hello . docker run --rm treeder/hello

Let's check the image size with:

docker images | grep treeder/hello

Result

The image is 258 MB, which is quite large for just a small Go binary. Now, let’s use a multi-stage build with this updated Dockerfile:

# Build stage FROM golang:alpine AS build-env RUN apk --no-cache add build-base git bzr mercurial gcc ADD . /src RUN cd /src && go build -o goapp # Final stage FROM alpine WORKDIR /app COPY --from=build-env /src/goapp /app/ ENTRYPOINT ./goapp

Build and run this new Docker image:

docker build -t treeder/hello . docker run --rm treeder/hello

Now check the size:

Result

It’s just 6.35 MB. Much more efficient!

In summary, multi-stage builds are highly effective and should be used nearly always to keep Docker images slim and optimized.

Be first in line for updates
and special pricing

Get early access to new features and exclusive discounts delivered straight to your inbox

Legal

Privacy PolicyTerms and ConditionsAcceptable Use Policy
NoVPS

© 2025 NoVPS Cloud LTD

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.