Use npm ci in CI and deployment. It installs exactly what the lockfile records, fails if the lockfile and package.json disagree, and never writes to either file. Use npm install on a developer machine when you intend to change dependencies, and review the lockfile diff that results.
What the documentation says
The npm docs list these differences for npm ci:
- The project must have an existing package-lock.json or npm-shrinkwrap.json.
- If dependencies in the lock do not match package.json, npm ci exits with an error instead of fixing the lock.
- If a node_modules folder exists, it is removed before the install begins.
- It never writes to package.json or any lockfile. Installs are essentially frozen.
Why that is a security property
Think about what a pipeline should be: a machine that reproduces a reviewed state. When it can quietly resolve new versions, it can ship something nobody reviewed.
With npm install in CI, a loose version range in package.json can resolve to a version published an hour ago. If that version is malicious, the pipeline fetches it, runs its install scripts with the pipeline's credentials, and bakes it into the artifact. With npm ci, the install is bound to the versions and integrity hashes recorded in the lockfile.
The lockfile stores, for each package, the version, the resolved location and an integrity string, which the docs describe as a sha512 or sha1 value for the artifact unpacked there. If the downloaded tarball does not match, the install fails.
Where each command fits
Local development, adding or upgrading a dependency. Use npm install, then read the lockfile diff before committing. New packages and changed resolved locations deserve a look.
Pull request checks. Use npm ci so reviewers test the committed state.
Release builds and deploys. Use npm ci. A failure here means the lockfile is stale or edited by hand, and that is a good failure.
Docker builds. Copy the manifest and lockfile first, run npm ci, then copy the source. This gives repeatable layers and a clear signal when the lock drifts.
Limits to keep in mind
- npm ci does not judge whether a locked package is safe. It reproduces whatever was locked, good or bad.
- Install scripts of locked packages still run unless you disable them, so consider your script policy separately.
- The lockfile must be committed. The docs say the file is intended to be committed so teammates, deployments and CI install the same dependencies.
- A lockfile edited by a stranger in a pull request is a risk. Review changes to resolved URLs and integrity values, not only version numbers.
A short checklist
- Commit the lockfile.
- Use npm ci in every automated install.
- Fail the build when npm ci errors, and fix the lock in a pull request.
- Review lockfile diffs for new packages, changed registries and odd tarball locations.
- Scan the locked set for known issues on each change.
Safeguard scans dependencies from manifests and lockfiles and can gate pull requests on the result, so the locked set gets checked each time it changes.
Quick check
Does npm ci update my lockfile?
No. It never writes to package.json or lockfiles, and it fails if they disagree.
What happens if I edit package.json and forget the lockfile?
npm ci exits with an error because the lock and package.json no longer match. Run npm install locally, review the diff and commit both files.
Sources
Last reviewed: 19 October 2026.