Multi-Stage Builds
LEVEL 0
The Problem
To build your Go/Java/TypeScript application, you need compilers, build tools, and dependencies. But to run it, you only need the compiled output.
Your image has 500MB of build tools that are never used at runtime. Wasteful.
LEVEL 1
The Concept — The Construction Site vs the House
The Concept
Building a house requires:
- Cranes
- Scaffolding
- Power tools
- Lumber piles
- Workers’ facilities
Living in a house requires:
- None of the above
You don’t leave the crane in the backyard when construction is done. You take only the finished house.
Multi-stage builds are the same. Stage 1 is the construction site (build). Stage 2 is the house (runtime). You take only what you need from Stage 1 into Stage 2.
LEVEL 2
The Mechanics — Multi-Stage Syntax
The Mechanics
Basic Multi-Stage
# Stage 1: Build
FROM node:18 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
# Stage 2: Runtime
FROM node:18-slim
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
CMD ["node", "dist/main.js"]
Key points:
- Multiple
FROMstatements AS buildernames the stageCOPY --from=buildercopies from that stage
Go Example (Extreme Reduction)
# Build stage
FROM golang:1.21 AS builder
WORKDIR /app
COPY . .
RUN CGO_ENABLED=0 go build -o main .
# Runtime stage
FROM scratch
COPY --from=builder /app/main /main
CMD ["/main"]
Result: Final image contains only the compiled binary. Can be under 10MB!
LEVEL 3
Benefits
Smaller Images
| Approach | Image Size |
|---|---|
| Node with all deps | 1.1 GB |
| Node multi-stage | 200 MB |
| Go single-stage | 800 MB |
| Go multi-stage | 10 MB |
Security
Fewer tools in the final image = smaller attack surface. No compiler vulnerabilities if there’s no compiler.
Faster Pulls
Smaller images transfer faster, deploy faster, scale faster.
LEVEL 4
Advanced Patterns
Multiple Named Stages
FROM ubuntu AS base
RUN apt-get update
FROM base AS development
RUN apt-get install -y dev-tools
FROM base AS production
RUN apt-get install -y --no-install-recommends minimal-deps
Targeting Specific Stages
docker build --target development -t myapp:dev .
docker build --target production -t myapp:prod .
Using External Images
COPY --from=nginx:alpine /etc/nginx/nginx.conf /etc/nginx/