Agent Wranglers

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

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.