Migrate to RunxBuild and earn up to $50 in hosting credit on your first deposit.

Calculate your savings
unxBuild

Docker Multistage Build: Smaller Images, Separate Build and Runtime

Sean

Platform Writer

Jul 05, 2026
5 min read

Docker multistage build uses multiple FROM statements in one Dockerfile to separate the build environment from the runtime environment. The final image only contains the runtime dependencies - 10x smaller typically per the Docker docs. The team that uses multistage builds has small, secure images without manual cleanup steps.

Docker Multistage Build: Smaller Images, Separate Build and Runtime

Table of contents

Single-stage vs multistage

Single-stage (everything in one image):

FROM golang:1.21
WORKDIR /app
COPY . .
RUN go build -o /app/server
CMD ["/app/server"]

Result: 800MB image (includes Go toolchain).

Multistage:

FROM golang:1.21 AS builder
WORKDIR /app
COPY . .
RUN go build -o /server

FROM gcr.io/distroless/static-debian12
COPY --from=builder /server /server
CMD ["/server"]

Result: 20MB image (only the compiled binary).

The team that uses multistage has tiny production images.

The COPY —from syntax

Copy artifacts from a previous stage:

FROM node:20 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM nginx:alpine
COPY --from=builder /app/dist /usr/share/nginx/html

The team that uses COPY --from=builder has the build output copied to the runtime stage.

Multiple build stages

FROM node:20 AS deps
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production

FROM node:20 AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build

FROM nginx:alpine
COPY --from=builder /app/dist /usr/share/nginx/html

The team that separates deps, build, and runtime stages has caching at each layer.

Naming stages

Use AS name to name stages:

FROM golang:1.21 AS builder
# ...

FROM alpine:3.19 AS runtime
COPY --from=builder /app/server /server

The team that uses named stages has readable Dockerfiles.

Build specific stage

docker build --target builder -t myapp:builder .

Build only up to the builder stage. Useful for debugging the build without producing the full image.

Build cache optimization

Each stage is cached independently:

FROM node:20 AS deps
COPY package*.json ./
RUN npm ci   # cached unless package.json changes

FROM node:20 AS builder
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build

The team that orders stages for cache hits has fast incremental builds.

Common runtime base images

  • gcr.io/distroless/static-debian12: ~2MB, no shell, no package manager.
  • alpine: ~5MB, includes shell + apk.
  • debian-slim: ~80MB, full Debian base.
  • ubuntu: ~100MB, full Ubuntu.

The team that picks distroless has smallest images + better security (fewer attack vectors).

FAQ

What’s the size difference between single-stage and multistage?

Typical: 10x smaller. Go app: 800MB -> 20MB. Node app: 1GB -> 50MB. The team that uses multistage has drastically smaller images.

Can I use multistage with BuildKit?

Yes - BuildKit (default in Docker 23+) has enhanced multistage support including parallel stage execution.

Do all stages get cached?

Yes - each stage is cached independently based on its inputs (FROM, COPY, RUN). The team that has well-ordered stages has fast rebuilds.

Can I copy from a previous image, not just stage?

Yes - COPY --from=otherimage:tag /path /dest. The team that copies artifacts from published images has flexible builds.

Should I use multistage for every Dockerfile?

Yes - multistage has no downside for production. For dev/test images that need the full toolchain, single-stage is fine.

If you are sizing the infrastructure for the kind of project this post covers, the RunxBuild hosting calculator is the right place to model the line items. The compute, the memory, the storage, the bandwidth, the database - each one is a separate number, and the team’s mental model for the platform is the sum of those numbers. The RunxBuild dashboard is where the team sees the actual usage in one place.

Useful related references:

#docker#multistage#build#dev-infra