Skip to content

avoid-dev-dependencies

npm devDependencies in a production Docker image: why npm install bloats the final stage and how --omit=dev fixes it.

On this page

A plain npm install in your Dockerfile's final stage installs everything — TypeScript, test runners, linters, build plugins — into an image whose only job is to run the app. devDependencies are routinely several times the size of the runtime dependencies they sit next to. This rule flags full dependency installs in the production stage.

What the rule catches

Dockerfile — typescript and jest ship to production
FROM node:22-slim
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
CMD ["node", "dist/server.js"]

Scanning this file reports:

⚠ WARN [docker-doctor/avoid-dev-dependencies]
  Running package install 'npm install' in the final stage without omitting devDependencies.

Why it matters

Dev dependencies in production are dead weight with a blast radius: hundreds of megabytes per pull, plus hundreds of packages' worth of vulnerability-scanner findings and supply-chain exposure for tools that will never execute. The runtime stage should hold exactly the packages require()d at run time. Build-time tooling belongs in a build stage that gets discarded — the pattern described in use-multi-stage.

How to fix it

For Node.js, run npm prune --production or install only production dependencies (npm ci --omit=dev) in the runtime stage.

Dockerfile — dev deps live and die in the build stage
FROM node:22-slim 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"]

Equivalents across ecosystems: yarn install --production, pnpm install --prod, pip install from a runtime-only requirements file, bundle install --without development test. Also prefer npm ci over npm install in images — it installs exactly what the lockfile says and fails loudly on drift, which is precisely what you want from a reproducible build.

Rule details

  • Rule keydocker-doctor/avoid-dev-dependencies
  • Category — Image Size
  • Default severitywarning
  • Applies to — Dockerfiles

Explain this rule from the CLI:

npx @docker-doctor/cli@latest rules explain docker-doctor/avoid-dev-dependencies

Change its severity — or turn it off — in your config file:

// docker-doctor.config.ts
export default {
  rules: {
    "docker-doctor/avoid-dev-dependencies": "off",
  },
};

Severity affects the health score: error findings cost more points than warning, and info costs the least.