Why npm install changes package-lock.json

Understand manifest reconciliation, npm lockfile versions, platform differences, and when npm ci is the appropriate reproducible-install command.

Best practices
Illustration accompanying a Node.js development guide

npm install can update package-lock.json while reconciling the requested dependency graph with package.json, npm's resolver, and the current configuration. A changed lockfile does not automatically mean every dependency was upgraded, nor should every change be dismissed as harmless formatting.

Manifest intent versus resolved versions

package.json describes dependencies and allowed versions. The lockfile records the resolved tree, including package versions and resolution information. When the existing lock satisfies the manifest, npm generally reuses it. Adding, removing, or changing a dependency can require a new resolution and corresponding lockfile edits.

An explicit npm update or npm audit fix can also alter the resolved graph. Ordinary installation's audit report does not itself mean npm automatically applied every suggested security fix.

npm versions and lockfile formats

Different npm generations write different lockfile formats:

lockfileVersion Common producing npm versions
1 npm 5 and 6
2 npm 7 and 8
3 npm 9 and later versions using the current format

A newer npm can enrich or convert an older lockfile, sometimes by consulting installed packages or registry metadata. npm 7 also introduced a hidden node_modules/.package-lock.json with different compatibility needs. That hidden file is not the repository's root lockfile.

Standardize the Node and npm versions used by developers and CI when unnecessary lockfile churn becomes a problem. A Node version manager helps, but npm can be updated separately, so check both versions.

Configuration and platform differences

Peer dependency policy, workspace layout, registry configuration, and flags such as --legacy-peer-deps or --install-links can change the installed tree. Optional dependencies may have operating-system or architecture constraints. A root lockfile is intended to support the project's supported environments, so review platform-specific changes rather than assuming missing optional packages are always acceptable.

Resolver bugs and incomplete lockfiles are possible too. If a change removes dependencies needed by another platform, reproduce it with the team's chosen npm version and investigate before committing it.

Use npm ci for a committed graph

npm ci

npm ci requires a lockfile, rejects a mismatch with package.json, and removes an existing node_modules directory before installation. npm's installer does not update the manifest or lockfile in this mode. Lifecycle scripts can still run and have their own side effects; this is not a promise that arbitrary project scripts cannot write files.

Use the same tree-affecting flags that created the lockfile. Project-level npm configuration can make those settings explicit for CI. Use npm install when deliberately changing dependencies, then commit the reviewed manifest and lockfile together.

Review and resolve changes

Inspect which packages and integrity/resolution entries changed, run relevant tests, and verify the supported environments. For a merge conflict, reconcile the intended manifest changes first and regenerate consistently; do not delete the lockfile reflexively, since doing so can re-resolve a much larger graph.

Applications should normally commit their root lockfile. A library's lockfile also helps its own development and testing, but downstream consumers do not use it to lock their entire installation. Keep intentional feature-related dependency updates with their corresponding lock changes rather than reserving all lockfile edits for dedicated upgrade branches.

See package-lock.json, npm install, and npm ci.

Get a tailored plan

Contact us

Join the community

Scan with WeChat
to join the community

Try Guance

Start online and pay only for what you use.

Get started

Choose a Guance plan

Code hosting