Multi-stage Builds
A Dockerfile with multiple FROM instructions. Each stage can copy artifacts from previous stages. Only the final stage's layers are in the shipped image.
Multi-stage = cooking in a messy kitchen, then plating only the finished dish in a clean restaurant. Guests (production) never see the dirty pots, flour everywhere, or secret recipe notes — only the final plate.
Use case: compile in a full SDK image, copy only the binary into a minimal runtime image. Example: FROM golang:1.21 AS builder; RUN go build -o app; FROM gcr.io/distroless/base; COPY --from=builder /app /app. The final image has no build toolchain — dramatically smaller and fewer attack surface vulnerabilities. COPY --from=stage_name or --from=0 (index) copies between stages.
Named stages (AS builder) allow COPY --from=builder. Stages can be targeted with docker build --target builder — useful for running tests in CI without building the final image. Distroless images (Google) contain only the runtime and app — no shell, no package manager, tiny attack surface. Alpine-based images (~5MB) are another minimal option but use musl libc which can cause subtle compatibility issues with glibc-compiled binaries. BuildKit can run independent stages in parallel. Multi-stage is the primary way to separate build dependencies from runtime dependencies in containerized applications.
Multi-stage builds let you use a fat build environment (Go SDK, JDK, Node with build tools) and produce a minimal runtime image. COPY --from=builder copies only what you need — the compiled binary, built assets. The shipped image has no compiler, no npm, no secrets used during build. I use FROM gcr.io/distroless/static for Go binaries — the final image is ~5MB with no shell or OS utilities, which dramatically reduces CVE exposure.
Build-time secrets (API keys, SSH keys) passed as ARG or ENV are baked into the layer — even if you delete them in a later step. Use BuildKit secret mounts: RUN --mount=type=secret,id=mysecret cat /run/secrets/mysecret. These never appear in any layer.