Multi-stage builds work by separating build-time tools from runtime needs. You define multiple stages with separate FROM statements, build your application in early stages with all necessary compilers and dependencies, then copy only the final artifacts into a minimal runtime image. This eliminates the bulk of build tools from your final container.
Key principles:
- Separate concerns: Early stages handle compilation, testing, and build processes. The final stage includes only what's needed to run the app.
- Use
COPY --from: Pull artifacts from earlier stages or external images into your final stage. - Pick lean base images for runtime: Use distroless images, Alpine, or scratch for the final stage to minimize size.
- Language-specific patterns: Compiled languages (Go, Rust, C) benefit most—copy the binary alone. Interpreted languages (Python, Node, Ruby) can minify code in one stage and copy production files to another.
Real example (Go): A Go app with the full toolchain is 1.1GB. Using a multi-stage build with a distroless runtime drops it to 28MB.
Official tutorials and docs:
- https://docs.docker.com/build/building/multi-stage/ — comprehensive guide with detailed examples
- https://docs.docker.com/guides/golang/build-images/ — walkthrough for Go with before/after size comparison
- https://docs.docker.com/get-started/docker-concepts/building-images/multi-stage-builds/ — beginner-friendly conceptual introduction
Sources:
- https://docs.docker.com/build/building/multi-stage/
- https://docs.docker.com/get-started/docker-concepts/building-images/multi-stage-builds/
- https://docs.docker.com/guides/golang/build-images/
There is a tool that is good for inspecting the contents of docker image layers.
You're likely thinking of dive. It's a standalone tool that lets you explore Docker image layers interactively—see what files are in each layer, their sizes, and identify what's contributing to bloat. It works on any image regardless of language.
There's also syft, which analyzes image contents and generates software bill of materials (SBOM).
If you're in the JVM ecosystem specifically, jib (by Google) is a build tool that creates optimized layered images, and some teams use it alongside inspection tools.