Multi-stage Builds

Multi-stage builds use one stage to compile your app and a second, minimal stage to ship only the finished result.

SyntaxFROM image AS stagename ... FROM smaller-image COPY --from=stagename /path /path

A multi-stage build uses several FROM instructions in one Dockerfile. Early stages do heavy work like compiling; the final stage copies only the finished artifacts, leaving build tools behind.

Why use them

  • Keep compilers, dev dependencies and source code out of the final image.
  • Produce dramatically smaller, more secure images.
  • Keep everything in a single Dockerfile.

How it works

Name a stage with AS build, then copy files from it in a later stage using COPY --from=build. Only the last stage becomes the final image.

Example

Example · dockerfile
# Stage 1: build the frontend
FROM node:20-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

# Stage 2: serve the built files with Nginx
FROM nginx:1.27-alpine
COPY --from=build /app/dist /usr/share/nginx/html
EXPOSE 80

When to use it

  • A Go team uses a multi-stage build so the final image ships only the compiled binary, not the Go toolchain (saving 600 MB).
  • A React team compiles assets in a Node.js stage and copies only the dist/ folder into an Nginx stage for serving.
  • A Java team runs Maven in one stage to build a JAR, then copies the JAR into a slim JRE image, excluding sources and test dependencies.

More examples

Go multi-stage build

Compiles the Go binary in a full Go image, then copies only the binary into a tiny Alpine runtime image.

Example · dockerfile
FROM golang:1.22-alpine AS builder
WORKDIR /src
COPY . .
RUN go build -o /api .

FROM alpine:3.19
COPY --from=builder /api /api
ENTRYPOINT ["/api"]

React + Nginx multi-stage

Builds the React app in a Node stage and serves only the static output from a minimal Nginx stage.

Example · dockerfile
FROM node:20-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM nginx:alpine
COPY --from=build /app/dist /usr/share/nginx/html

Named stages for targeted builds

Uses --target to stop the build at a named stage, which is useful for running tests without building the final image.

Example · bash
# Build only up to the test stage during CI
docker build --target test -t myapp:test .

# Build the full production image
docker build --target production -t myapp:prod .

Discussion

  • Be the first to comment on this lesson.