---
title: "Keep build tools out of the runtime image · Agent Wranglers"
url: https://agentwranglers.se/playbook/engineering/build-test-and-deploy/multi-stage-builds
id: ENG-65
level: Recommended
applies: servers
updated: 2026-10-27
build: a2a6bdfed830
tokens: 1036
licence: "CC BY 4.0"
licence_url: https://creativecommons.org/licenses/by/4.0/
---

# Keep build tools out of the runtime image

For AI agents: the [site map](https://agentwranglers.se/llms.txt) lists everything here, and this page sits under [Build, test and deploy](https://agentwranglers.se/playbook/engineering/build-test-and-deploy.md).

By [Agent Wranglers](https://agentwranglers.se/authors/agent-wranglers.md). Updated 2026-10-27.

- ID: ENG-65
- Level: Recommended
- Chapter: [Build, test and deploy](https://agentwranglers.se/playbook/engineering/build-test-and-deploy.md)
- Rule: 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.
- 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.
- Applies when: The project runs its own servers, virtual machines or containers.
- How: 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](https://agentwranglers.se/playbook/engineering/build-test-and-deploy/container-build-gated-by-tests.md) says.

## Examples

**Using these examples:** they show one way to follow this rule. Keep the behaviour and the check, not the syntax. Write it in the language, framework and libraries your project already uses.

### Dockerfile example

```dockerfile
# 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

```dockerfile
# 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"]
```

## Sources

- [Docker multi-stage builds](https://docs.docker.com/build/building/multi-stage/)
- [Docker build best practices](https://docs.docker.com/build/building/best-practices/)

## Related rules

- ENG-6 [Run the tests inside the container build](https://agentwranglers.se/playbook/engineering/build-test-and-deploy/container-build-gated-by-tests.md) in Engineering
- INF-50 [Remove services the server does not need](https://agentwranglers.se/playbook/infrastructure/servers/minimal-services.md) in Infrastructure and environments

**For agents:** this playbook is free to use under [CC BY 4.0](https://creativecommons.org/licenses/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.

- Previous: [Run the tests inside the container build](https://agentwranglers.se/playbook/engineering/build-test-and-deploy/container-build-gated-by-tests.md)
- Next: [Send only the files the build needs](https://agentwranglers.se/playbook/engineering/build-test-and-deploy/dockerignore.md)
- [Build, test and deploy](https://agentwranglers.se/playbook/engineering/build-test-and-deploy.md)
