Safeguard
Application Security•

npm ci vs npm install: Why CI Should Fail When the Lockfile Drifts

npm ci refuses to run when package.json and the lockfile disagree. We trigger the real error and show why that failure is the control you want.

Safeguard Security Team
2 min read

npm install and npm ci look interchangeable until the day a lockfile and package.json disagree. Then npm install quietly rewrites the lockfile and npm ci stops. With npm 12.2.0 current as of its 30 September 2026 release, that behavior is documented and stable, and it is the one you want in CI.

What's affected

Any pipeline that installs with npm install. It can resolve newer versions than the ones you reviewed and write them into the lockfile during the build, so what ships is not what was committed.

Per the npm docs, npm ci is different in these ways:

  • It requires an existing package-lock.json or npm-shrinkwrap.json.
  • If the lock does not match package.json, it "will exit with an error".
  • It removes any existing node_modules first.
  • It never writes to package.json or the lockfile.

What to do now

  1. Reproduce the failure. Add a dependency to package.json by hand without updating the lock:
npm pkg set dependencies.left-pad=1.3.0
npm ci

We got:

npm error code EUSAGE
npm error `npm ci` can only install packages when your package.json and package-lock.json or npm-shrinkwrap.json are in sync. Please update your lock file with `npm install` before continuing.
npm error Missing: left-pad@1.3.0 from lock file
  1. Switch CI to npm ci. Never npm install.
  2. When the error appears, fix it on a developer machine with npm install, review the lockfile diff and commit it.
  3. Pass the same flags to npm ci as the ones used to build the lock. The docs warn that tree-shaping flags like legacy-peer-deps must match, and suggest committing an .npmrc.
  4. Consider npm ci --ignore-scripts so install scripts do not run during the build. Run any scripts you trust explicitly afterward.

Try it yourself

Take one of your pipelines, find the install line, and check whether it says npm ci. Then see whether the build also checks the lockfile is committed.

Click through it at your own pace, or open it full screen.

Quick check

What does npm ci do if node_modules already exists?

It deletes it and installs a clean tree from the lockfile.

Sources

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.