Package.json vs package-lock.json in Node.js: Key Differences and Usage
package.json lists your project's direct dependencies and metadata, while package-lock.json locks the exact versions of all installed packages including nested ones to ensure consistent installs.Quick Comparison
This table summarizes the main differences between package.json and package-lock.json in Node.js projects.
| Aspect | package.json | package-lock.json |
|---|---|---|
| Purpose | Lists direct dependencies and project info | Locks exact versions of all installed packages |
| Content | Dependency names with version ranges | Full dependency tree with exact versions and resolved URLs |
| Created/Updated | Manually or via npm commands | Automatically generated/updated by npm |
| Human readability | Easily readable and editable | More detailed and less human-friendly |
| Version control | Always committed to repo | Should be committed to ensure consistent installs |
| Effect on install | Defines what to install | Ensures exact versions are installed |
Key Differences
package.json is the main file where you declare your project's metadata like name, version, scripts, and most importantly, the direct dependencies your project needs. It uses version ranges (like ^1.2.3) to specify acceptable versions, allowing flexibility when installing packages.
On the other hand, package-lock.json is automatically created by npm when you install packages. It records the exact versions of every package installed, including nested dependencies, along with their resolved URLs and integrity hashes. This file ensures that every time someone installs your project dependencies, they get the exact same versions, preventing unexpected bugs from version changes.
While package.json is meant to be human-readable and editable, package-lock.json is more detailed and not usually edited manually. Both files should be committed to version control to maintain consistency across different environments.
package.json Example
{
"name": "my-app",
"version": "1.0.0",
"scripts": {
"start": "node index.js"
},
"dependencies": {
"express": "^4.18.2"
}
}package-lock.json Equivalent
{
"name": "my-app",
"version": "1.0.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "my-app",
"version": "1.0.0",
"dependencies": {
"express": "4.18.2"
}
},
"node_modules/express": {
"version": "4.18.2",
"resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz",
"integrity": "sha512-...",
"dependencies": {
"accepts": "~1.3.8"
}
}
},
"dependencies": {
"express": {
"version": "4.18.2",
"resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz",
"integrity": "sha512-...",
"requires": {
"accepts": "~1.3.8"
}
}
}
}When to Use Which
Choose package.json to define your project's direct dependencies, scripts, and metadata. It is the file you edit to add or update packages.
Always commit package-lock.json to your repository to lock down the exact versions of all dependencies and ensure consistent installs across all environments and team members.
In summary, package.json is for declaring what you want, and package-lock.json is for locking what you actually get.
Key Takeaways
package.json lists your project's direct dependencies with version ranges and metadata.package-lock.json locks exact versions of all installed packages including nested dependencies.package.json is manually edited; package-lock.json is auto-generated by npm.package.json to declare dependencies and package-lock.json to ensure exact installs.