Skip to content

/flags/npm/npm-install-omit-dev

npm install --omit=dev: install without devDependencies (replaces --production)

verified onenvironmentlocal · windows 10.0.26200 arm64 · GNU bash 5.3.15 (Git Bash) · 11.19.0updated
tool
npm
command
npm install, npm ci
flag
--omit=dev|optional|peer, --include=TYPE
default
nothing omitted ('dev' when NODE_ENV=production)

npm install --omit=dev (and npm ci --omit=dev) installs only the packages needed at runtime: everything under devDependencies, and packages reachable only through them, is left out of node_modules. It is the modern replacement for --production and --only=prod, which still work but print a deprecation warning. The lockfile is not changed; it still describes the full tree.

With and without the flag

bash
cat > package.json <<'EOF'
{
  "name": "demo",
  "version": "1.0.0",
  "dependencies": { "is-number": "7.0.0" },
  "devDependencies": { "is-odd": "3.0.1" }
}
EOF
npm install --no-audit --no-fund >/dev/null 2>&1
echo "--- npm install"
ls node_modules
echo "--- npm ci --omit=dev"
npm ci --omit=dev --no-audit --no-fund >/dev/null 2>&1
ls node_modules
echo "--- the old flag"
npm ci --production --no-audit --no-fund 2>&1 | grep -i "warn"
echo "--- NODE_ENV=production"
NODE_ENV=production npm ci --no-audit --no-fund >/dev/null 2>&1
ls node_modules

Output

--- npm install
is-number
is-odd
--- npm ci --omit=dev
is-number
--- the old flag
npm warn config production Use `--omit=dev` instead.
--- NODE_ENV=production
is-number

npm ci deletes node_modules first, so each run starts clean. With --omit=dev, --production or NODE_ENV=production, only is-number is installed.

Values

OptionEffect
--omit=devSkip devDependencies
--omit=optionalSkip optionalDependencies (native add-ons that are allowed to fail)
--omit=peerDo not install peer dependencies automatically
--omit=dev --omit=optionalThe option can be repeated
--include=devInstall devDependencies even when NODE_ENV=production
--production / --only=prodDeprecated aliases of --omit=dev
omit=dev in .npmrcMake it the default for the project or user

If a type is both included and omitted, --include wins. That is how a build stage can override NODE_ENV=production from a base image.

In a Dockerfile

dockerfile
FROM node:24-slim
WORKDIR /app
ENV NODE_ENV=production
COPY package.json package-lock.json ./
RUN npm ci --omit=dev
COPY . .
CMD ["node", "server.js"]

When the image builds the app (TypeScript, Vite, Next.js), use two stages: npm ci --include=dev and the build in the first, npm ci --omit=dev plus the build output in the second. Running npm prune --omit=dev after the build is the one-stage alternative.

Pitfalls

  • A package the app requires at runtime but listed under devDependencies works locally and fails in production with Cannot find module. Move it with npm install pkg --save-prod.
  • Lifecycle scripts such as prepare or postinstall that call dev tools (husky, tsc) fail when those tools are omitted; guard them or use --ignore-scripts for the production install.
  • NODE_ENV=production set globally in CI makes every npm install omit dev dependencies, so tests suddenly cannot find jest or vitest.
  • npm ci versus npm install behaviour is compared in npm ci vs npm install.

FAQ

What is the difference between --omit=dev and --production?

They do the same thing for devDependencies. --production is the old name and prints a warning telling you to use --omit=dev; --omit can also skip optional and peer dependencies.

Does NODE_ENV=production change npm install?

Yes. When NODE_ENV is production, the default of --omit becomes dev, so devDependencies are skipped even without the flag. That surprises people whose Docker build needs TypeScript or a bundler; pass --include=dev for that step.

Does --omit=dev change package-lock.json?

No. The lockfile keeps the full tree including devDependencies; the flag only decides what is written to node_modules, so the same lockfile serves development and production installs.

Sources