use-multi-stage
How multi-stage Docker builds keep compilers and build tools out of your production image and cut image size dramatically.
On this page
A single-stage Dockerfile ships everything the build needed: compilers, dev dependencies, source code, package-manager caches. None of that runs in production — it just rides along in every pull. This rule suggests splitting build and runtime into separate stages when a Dockerfile shows build activity but only one FROM.
What the rule catches
FROM node:22
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
CMD ["node", "dist/server.js"]Scanning this file reports:
ℹ INFO [docker-doctor/use-multi-stage]
Only one build stage (FROM) was detected, but build instructions were found. Multi-stage builds can significantly reduce final image size.Why it matters
The runtime image should contain the app and its runtime, nothing else. Multi-stage builds get you there without shell gymnastics: one stage has the full toolchain, the final stage starts from a clean base and COPY --from pulls in only the built artifacts. The payoff is smaller images (often by hundreds of megabytes), faster pulls and cold starts, and a much smaller attack surface — a compiler in a production container only ever helps an attacker.
How to fix it
Use multi-stage builds (multiple FROM statements) to separate build dependencies from the runtime image and reduce size.
FROM node:22 AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM node:22-slim
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
COPY --from=build /app/dist ./dist
USER node
CMD ["node", "dist/server.js"]Everything in the build stage — dev dependencies, source, caches — is discarded; only what the final stage explicitly copies survives. For compiled languages the gap is even larger: a Go or Rust binary can run FROM gcr.io/distroless/static, taking the image from gigabytes to tens of megabytes.
Rule details
- Rule key —
docker-doctor/use-multi-stage - Category — Performance
- Default severity —
info - Applies to — Dockerfiles
Explain this rule from the CLI:
npx @docker-doctor/cli@latest rules explain docker-doctor/use-multi-stageChange its severity — or turn it off — in your config file:
// docker-doctor.config.ts
export default {
rules: {
"docker-doctor/use-multi-stage": "off",
},
};Severity affects the health score: error findings cost more points than warning, and info costs the least.