Introduction

Docker multi-stage builds allow you to use multiple FROM statements in your Dockerfile. Each FROM instruction can use a different base, and each of them begins a new stage of the build.

Prerequisites

  • Docker installed (version 17.05+)
  • Basic understanding of Dockerfiles
  • A sample application (we'll use a Go app)
  • Step 1: The Problem with Single-Stage Builds

    A typical single-stage Dockerfile for a Go application:

    FROM golang:1.21
    

    WORKDIR /app

    COPY . .

    RUN go build -o myapp .

    CMD ["./myapp"]

    This results in an image of ~800MB because it includes the entire Go toolchain.

    Step 2: Multi-Stage Build Solution

    Now let's use multi-stage builds:

    # Build stage
    

    FROM golang:1.21 AS builder

    WORKDIR /app

    COPY go.mod go.sum ./

    RUN go mod download

    COPY . .

    RUN CGO_ENABLED=0 GOOS=linux go build -o myapp .

    # Production stage

    FROM alpine:3.19

    RUN apk --no-cache add ca-certificates

    WORKDIR /root/

    COPY --from=builder /app/myapp .

    CMD ["./myapp"]

    Result: Image size reduced from ~800MB to ~15MB!

    Step 3: Building and Testing

    # Build the image
    

    docker build -t myapp:multi-stage .

    # Check the image size

    docker images myapp

    # Run the container

    docker run -p 8080:8080 myapp:multi-stage

    Step 4: Advanced Patterns

    Using Build Arguments

    FROM golang:1.21 AS builder
    

    ARG VERSION=dev

    RUN go build -ldflags="-X main.version=${VERSION}" -o myapp .

    Caching Dependencies

    Copy dependency files first to leverage Docker layer caching:

    COPY go.mod go.sum ./
    

    RUN go mod download

    COPY . .

    Best Practices

  • Always use specific base image tags
  • Leverage build cache by ordering instructions correctly
  • Use .dockerignore to exclude unnecessary files
  • Use scratch or distroless for minimal images
  • Name your build stages for clarity

Conclusion

Multi-stage builds are essential for creating production-ready Docker images. They reduce image size, minimize attack surface, and improve deployment speed.