If you've worked with Node.js or npm, you've definitely seen package.json and package-lock.json sitting side by side in your project. Many developers know they're related to dependencies, but not everyone clearly understands why both exist and what makes them different.
Let's break it down.
What is package.json?
package.json is the project manifest file. It describes your project and lists the dependencies your application needs.
It typically includes:
- Project name and version
- Scripts (
npm start,npm build, etc.) - Dependencies and dev dependencies
- Metadata (author, license, etc.)
Example
{
"name": "my-app",
"version": "1.0.0",
"dependencies": {
"express": "^4.18.2"
}
}
Key Point
When you write "express": "^4.18.2", the ^ means npm can install any compatible version, such as 4.18.2, 4.19.0, or any 4.x.x release.
This means installs may differ over time, which can cause problems.
What is package-lock.json?
package-lock.json is automatically generated by npm. It locks the exact versions of every installed dependency, including sub-dependencies.
It ensures:
- Same dependency tree across all environments
- Same versions for everyone on the team
- Reproducible installs across machines
Example (simplified)
{
"dependencies": {
"express": {
"version": "4.18.2",
"resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz",
"integrity": "sha512-..."
}
}
}
This file guarantees that everyone installs the exact same version, even if package.json allows flexibility.
Main Differences
| Feature | package.json | package-lock.json |
|---|---|---|
| Purpose | Defines dependencies | Locks exact versions |
| Created by | Developer | npm automatically |
| Should you edit? | Yes | No |
| Version flexibility | Yes | No |
| Included in Git? | Yes | Yes |
| Controls sub-dependencies | No | Yes |
Why Both Files Are Needed
Think of it like this:
package.json→ What you wantpackage-lock.json→ What you actually got
Example scenario:
- You install today → version 1.2.3
- Your teammate installs tomorrow → version 1.2.5
- App breaks due to subtle differences
With package-lock.json, everyone installs exactly 1.2.3. No surprises.
When Does package-lock.json Update?
It updates when:
- You run
npm install - You add or remove packages
- You run
npm update
Should You Commit package-lock.json?
Yes, always commit it to Git.
Benefits:
- Reproducible builds
- Faster installs (npm can skip resolution)
- Prevents "works on my machine" issues
Quick Analogy
package.json= Shopping listpackage-lock.json= Receipt with exact brands and quantities
Conclusion
Both files serve different but complementary purposes:
- Use package.json to declare what dependencies you need
- Use package-lock.json to guarantee everyone gets the same versions
Never delete package-lock.json unless you intentionally want to regenerate your entire dependency tree.
Tagged with
Written by
DebuggerMe TeamThe DebuggerMe team builds developer tools, writes technical content, and helps teams ship better software.
Related Articles
All articles →Node.js 22 Is Here. Everything You Need to Know
Node.js 22 lands as the new LTS with native TypeScript type-stripping, a built-in test runner improvements, WebSocket client, and the much-anticipated require(esm) support. Here's a practical breakdown.
TypeScript 5.8 Major Speed Up
TypeScript 5.8 introduces return type check optimizations and compile time improvements, making local development faster.
React 19 Stable Is Finally Here
React 19 has entered stable release, introducing the React Compiler, server actions, and cleaner async form handling hooks.