Multi-stage builds

A multi-stage Dockerfile has several FROM lines: the first stages compile with the full toolchain, the last one copies only the result. Compilers and sources never reach the final image.

How it works

Name a stage with FROM golang:1.22 AS build, then COPY --from=build /out/api /api in a later stage. Only the last stage, or the one chosen with --target, becomes the image; the others stay in the build cache.

What breaks

The final stage must hold what the program needs to run. A binary linked against glibc does not start on alpine or scratch ("no such file or directory"), and a Node.js app needs node in the final base image.

In a Dockerfile

FROM golang:1.22 AS build
WORKDIR /src
COPY . .
RUN CGO_ENABLED=0 go build -o /out/api ./cmd/api

FROM gcr.io/distroless/static-debian12:nonroot
COPY --from=build /out/api /api
ENTRYPOINT ["/api"]

See it break, then fix it

Write the Dockerfile or the compose file, type the docker commands, and watch a simulated server run them through reboots, upgrades and traffic. Free to start.