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 updateor 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.jsonlists acceptable ranges;package-lock.jsonrecords exact installed versions.- Commit it, always, for apps.
- Use
npm cifor 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
What Is WSL? Running Linux on Windows, Explained
WSL lets you run a real Linux system inside Windows without dual-booting or a separate virtual machine to manage. What it is, why web developers use it, how to install it, where your files live, and the performance and networking gotchas.
What Is an IDE? Code Editors vs IDEs Explained
An IDE (integrated development environment) puts everything you need to write software in one app: editor, file browser, terminal, debugger, git and more. How it differs from a plain code editor, the popular options, cloud IDEs, and where AI fits in.