Skip to content
Back to Maintenance & LTS

Lockfile Management

Commit, resolve conflicts, and keep lockfiles healthy so installs are reproducible and fast.

Why

The lockfile is the single source of truth for what actually installs — without it, npm install produces a different tree on every machine and every CI run, and "works on my machine" becomes "fails in prod." Committing the lockfile makes installs reproducible, deterministic, and fast (no resolution step). The lockfile also pins transitive deps, so a dependency can't push a breaking transitive bump under you. The cost is merge conflicts on a JSON file, which are mechanical to resolve — and the cost of NOT committing is non-reproducible builds, which is far worse. Every modern package manager (npm, pnpm, yarn, pip, cargo, go) supports and recommends a committed lockfile.

When

Always commit the lockfile. Resolve conflicts whenever a merge touches package.json or the lockfile.

How

1. Commit the lockfile: add package-lock.json (or pnpm-lock.yaml / yarn.lock) to git, never gitignore it
2. On conflict: accept either side's package.json, then run npm install --package-lock-only to regenerate
3. Verify the regenerated lockfile installs clean: rm -rf node_modules && npm ci (ci = clean install from lockfile)
4. Use npm ci (not npm install) in CI — it fails if the lockfile is out of sync with package.json, catching drift
5. For monorepos: use a single root lockfile (pnpm workspaces) rather than per-package lockfiles
6. Periodically refresh: npm install --package-lock-only && npm audit fix to pull security patches into the lock

Example

# .gitignore — DO NOT ignore the lockfile
# (remove package-lock.json from .gitignore if present)
node_modules/
# package-lock.json  <- committed, not ignored

# CI uses ci (clean install) — fails on lockfile drift
# .github/workflows/ci.yml
- run: npm ci
- run: npm run build

# Resolve a lockfile merge conflict
git merge feature-branch
# CONFLICT in package-lock.json
git checkout --theirs package.json   # or --ours, then:
npm install --package-lock-only      # regenerate lockfile from resolved package.json
rm -rf node_modules && npm ci         # verify clean install
git add package.json package-lock.json
git commit

# Refresh security patches into the lockfile
npm audit fix --package-lock-only
git add package-lock.json && git commit -m "chore: security lockfile refresh"

Common Problems

  • ⚠gitignoring the lockfile — installs differ between dev and CI, and a transitive dep bumps a breaking change in prod only.
  • ⚠Using npm install in CI instead of npm ci — it silently updates the lockfile, masking drift instead of failing on it.
  • ⚠Manually editing the lockfile to force a version — it's regenerated on next install and your edit silently vanishes.

Best Practices

  • ✓Always commit the lockfile and use npm ci in CI — reproducible installs are the foundation of reproducible builds.
  • ✓Resolve lockfile conflicts by regenerating (npm install --package-lock-only), never by hand-merging JSON.
  • ✓Run npm audit fix --package-lock-only weekly to pull security patches into the lock without changing package.json.