Blog
4 min read

What Is package-lock.json? (And Should You Commit It?)

package.json says which versions your app accepts; package-lock.json records exactly which versions were installed. Why the lock file exists, why you should commit it, npm install vs npm ci, fixing merge conflicts in it, and the equivalent files for pnpm, Yarn and Bun.

Open any JavaScript project and next to package.json you'll find package-lock.json — thousands of lines nobody seems to have written. It looks like clutter. It's actually one of the most important files in the project.

(Background: what are npm and package.json?)

package.json: what you accept

In package.json, dependencies usually have ranges, not exact versions:

"dependencies": {
  "react": "^19.1.0",
  "zod": "~4.1.2"
}

^19.1.0 means "19.1.0 or any later 19.x." ~4.1.2 means "4.1.2 or any later 4.1.x." (Semantic versioning explained)

So two people running npm install a month apart could get different versions — and so could your production server. And that's just your direct dependencies; each of those has its own dependencies with ranges, hundreds deep.

package-lock.json: what you actually got

The lock file records the exact version of every package installed — direct and indirect — plus where it came from and a checksum (integrity) to verify it wasn't tampered with:

"node_modules/react": {
  "version": "19.1.1",
  "resolved": "https://registry.npmjs.org/react/-/react-19.1.1.tgz",
  "integrity": "sha512-..."
}

With the lock file, everyone — you, your teammates, CI, production, an AI agent — installs the same exact tree. "Works on my machine" bugs from version drift disappear.

Should you commit it?

Yes, for apps. Always commit package-lock.json. Don't add it to .gitignore. (What is .gitignore?)

(Library authors publishing to npm sometimes debate this, but even then the lock file doesn't get published and committing it helps contributors. For an app, there's no debate.)

npm install vs npm ci

npm install npm ci
Reads package.json and lock file Lock file only
Can update lock file Yes No — fails if out of sync
Deletes node_modules first No Yes
Use for Adding/updating packages while developing CI, production builds, deploys

In deploy scripts and CI, use npm ci. It installs exactly what's locked, fails loudly if package.json and the lock file disagree, and is faster on clean machines.

When the lock file changes

It updates when you:

  • Add a package: npm install zod
  • Remove one: npm uninstall zod
  • Update: npm update or install a new version

Commit those lock-file changes in the same commit as the package.json change. Review them occasionally — a huge diff for a small change can mean something unexpected got upgraded. (Update dependencies safely)

Merge conflicts in package-lock.json

Don't try to resolve them by hand. Take either side, then let npm regenerate it:

git checkout --theirs package-lock.json   # or --ours
npm install
git add package-lock.json

npm re-resolves the tree to match the merged package.json. (Merge conflicts explained)

"Should I delete it to fix an error?"

Deleting the lock file and reinstalling is a common suggestion for strange errors, and it sometimes works — because it upgrades everything at once to the latest allowed versions. That's also why it's risky: you might fix one problem and introduce three. Try deleting only node_modules first. If you do regenerate the lock file, test properly before deploying. (npm ERESOLVE errors)

The lock file is a security tool

Pinned versions and integrity hashes mean a newly published malicious version of a dependency won't silently arrive in your next deploy. Combined with release-age delays and audits, it's a key part of supply-chain safety. (npm supply chain security, npm audit)

Other package managers

Same idea, different file — use only one per project:

Package manager Lock file
npm package-lock.json
pnpm pnpm-lock.yaml
Yarn yarn.lock
Bun bun.lock

Two different lock files in one repo means two package managers are in use — pick one and delete the other. (npm vs pnpm vs Yarn vs Bun)

The summary

  • package.json lists acceptable ranges; package-lock.json records exact installed versions.
  • Commit it, always, for apps.
  • Use npm ci for CI and deploys.
  • Resolve lock-file conflicts by regenerating with npm install.
  • One package manager, one lock file.

EasySpawn builds and runs your app on the same Linux server where Claude Code develops it, so the locked dependency tree you test is exactly what you deploy. See how it works or join the waitlist.

Related: What Are npm and package.json? · Semantic Versioning Explained · npm Supply Chain Security · Cannot Find Module

Keep reading