Safeguard
Developer Tools•

npm ci vs npm install when AI edits your dependencies

Why CI should use npm ci, how it catches a manifest and lockfile mismatch, and how that limits what an AI-edited package.json can quietly change.

Safeguard Security Team
3 min read

Use npm ci in CI and deploys, and reserve npm install for deliberate local changes. npm ci installs exactly what the lockfile says and fails if the lockfile and package.json disagree, so an AI assistant that edits one without the other cannot slip a different dependency tree into a build.

What the two commands do differently

The npm documentation describes npm ci as meant for automated environments where you want a clean, reproducible install. In contrast with npm install:

  • It needs an existing package-lock.json or npm-shrinkwrap.json.
  • If the lockfile does not match package.json, it exits with an error instead of updating the lockfile.
  • It cannot add individual dependencies.
  • It removes any existing node_modules first.
  • It never writes to package.json or the lockfiles.

npm install resolves versions, may update the lockfile, and can add packages. That flexibility is what you want while developing and what you do not want in a pipeline.

Why this matters with AI assistants

Assistants frequently edit package.json to add a library, then leave the lockfile stale or regenerate it wholesale. Two bad outcomes follow.

  1. The build resolves fresh versions at install time, so what you tested is not what you ship.
  2. A regenerated lockfile changes dozens of transitive packages in a diff nobody reads.

With npm ci, the first problem becomes a loud failure. The second still needs a human to look at the lockfile diff.

A workable setup

  1. Commit the lockfile.
  2. Run npm ci in every pipeline.
  3. Require review for any change to the manifest or lockfile.
  4. Turn on a dependency review check so added and updated packages, including indirect ones, show up on the pull request.

GitHub's dependency review shows added, removed and updated dependencies with release dates, covers lockfile changes to indirect dependencies, and can fail a pull request on vulnerable packages.

One caveat

The npm docs note that if a lockfile was created with flags that change the tree, such as legacy peer dependency handling, you need to pass the same flags to npm ci. A project level .npmrc keeps them consistent.

Also remember that npm ci still runs package lifecycle scripts after installing. A frozen install makes the tree predictable; it does not make the packages trustworthy.

Common mistakes

Teams sometimes run npm install in CI because it is the habit, which silently rewrites the lockfile during the build. Others delete the lockfile when a merge conflict appears, then let the assistant regenerate it. Both throw away the review you did earlier. Resolve lockfile conflicts by rebasing and regenerating from the reviewed manifest, then read the resulting diff before merging.

Quick check

Does npm ci protect against a malicious package that is already in the lockfile?

No. It guarantees you install what was locked, not that the locked packages are safe. Pair it with review of additions and vulnerability scanning.

Sources

Last reviewed: 19 October 2026.

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.