package-lock.json
The lock file pins exact versions for reproducible installs.
npm cipackage-lock.json is generated automatically by npm. While package.json lists version ranges, the lock file records the exact version of every package (and sub-dependency) that was installed.
Why it matters
It guarantees that everyone — and every server — installs identical versions, avoiding the classic "works on my machine" problem.
Always commit package-lock.json to git.
Example
# npm install may update the lock file
npm install
# npm ci installs EXACTLY what the lock file says
# (deletes node_modules first — great for CI)
npm ciWhen to use it
- A staging deploy installs identical versions to production because `package-lock.json` is committed to git and `npm ci` uses it verbatim.
- A debugging session compares `package-lock.json` between a working and a broken build to find a dependency that auto-upgraded between deploys.
- A monorepo sync script detects when `package-lock.json` is newer than `node_modules` and re-runs `npm ci` to keep the install current.
More examples
Why package-lock.json exists
Illustrates the difference between the range in `package.json` and the exact pinned version in `package-lock.json`.
// package.json specifies a range:
// "express": "^4.18.0"
// package-lock.json records the EXACT version installed:
// "express": {
// "version": "4.18.2",
// "resolved": "https://registry.npmjs.org/express/-/...",
// "integrity": "sha512-..."
// }npm install vs npm ci
Contrasts `npm install` (may update the lock file) with `npm ci` (strict lock file enforcement for reproducibility).
# npm install: resolves ranges, may update lock file
npm install
# npm ci: uses lock file exactly, fails if it mismatches package.json
# Faster for CI because it skips resolution
npm ciCommit the lock file
Explains that apps should commit the lock file for reproducibility while libraries typically should not.
# Always commit package-lock.json (for apps)
git add package.json package-lock.json
git commit -m 'chore: add express 4.18.2'
# Libraries typically .gitignore the lock file
# so consumers resolve their own dependency tree
Discussion