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.