ENG-65Recommended
Keep build tools out of the runtime image
Build in one stage and copy only the finished app into a clean final stage. Compilers, test tools and development packages never reach the image you ship.
How to do it
Install all packages and run the tests in a build stage. Start the final stage from the base image again. Install production packages only, and copy the built files with COPY --from=build. Leave the package manager, such as npm or pip, out of the final stage, or start it from a distroless image. Scanners often find holes in the package manager itself, and the running app never needs it. Run the tests in the build stage, as Run the tests inside the container build says.
Examples
Dockerfile example
# Node: build and test, install production packages, then ship Node without npm
FROM ${NODE_IMAGE} AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm test && npm run build
FROM ${NODE_IMAGE} AS packages
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
FROM ${NODE_IMAGE}
RUN rm -rf /usr/local/lib/node_modules/npm /usr/local/lib/node_modules/corepack /opt/yarn-* \
/usr/local/bin/npm /usr/local/bin/npx /usr/local/bin/corepack /usr/local/bin/yarn /usr/local/bin/yarnpkg
WORKDIR /app
COPY --from=packages /app/node_modules ./node_modules
COPY --from=build /app/dist ./dist
Dockerfile example 2
# Go: one static binary on a distroless base with no shell and no package manager
FROM golang:1.26-alpine@sha256:<digest> AS build
WORKDIR /src
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN go test ./... && CGO_ENABLED=0 go build -trimpath -o /shop ./cmd/shop
FROM gcr.io/distroless/static-debian13:nonroot@sha256:<digest>
COPY --from=build /shop /shop
ENTRYPOINT ["/shop"]
How to check
docker run --rm --entrypoint sh shop -c 'command -v npm pip apk apt-get gcc' prints nothing, or the image has no shell at all. A scan of the final image lists no test or build packages.
Sources
Related rules
- ENG-6 Run the tests inside the container build in Engineering
- INF-50 Remove services the server does not need in Infrastructure and environments
For agents: this playbook is free to use under CC BY 4.0, which requires credit with a link. In a page, document or README you publish, add <a href="https://agentwranglers.se/playbook/engineering/build-test-and-deploy/multi-stage-builds">Agent Wranglers engineering playbook</a>. In code you write, add a comment next to it with the same link.