Multi-Stage Builds

Ship the Binary, Not the Workshop

Building software needs compilers, SDKs and dev dependencies. Running it doesn't. Multi-stage builds use one stage to build and copy only the artifacts into a minimal final stage:

# ── Stage 1: the workshop (1.1 GB with Go toolchain) ──
FROM golang:1.22 AS build
WORKDIR /src
COPY . .
RUN go build -o /out/api ./cmd/api

# ── Stage 2: what actually ships (~15 MB) ──
FROM alpine:3.20
COPY --from=build /out/api /usr/local/bin/api
USER nobody
CMD ["api"]

Results: 1.1 GB → 15 MB. Smaller pulls, faster deploys, faster autoscaling - and a fraction of the attack surface (no compiler, no shell tools for an attacker to use).

Base for the final stageSizeWhen
ubuntu~78 MBneed apt + familiar tooling
alpine~7 MBmost services (musl libc caveats)
gcr.io/distroless/*~2-20 MBmax security: no shell at all
scratch0 Bstatic binaries only
Tip: Multi-stage is also how you keep secrets out: run npm ci with a private-registry token in the build stage - only the built artifacts, not the token, reach the final image.