-
Notifications
You must be signed in to change notification settings - Fork 4k
docs(npm-install): explain package-lock.json behavior #8797
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
docs(npm-install): explain package-lock.json behavior #8797
Conversation
|
|
||
| When you run `npm install` without arguments, npm verifies that `package.json` and `package-lock.json` are in sync: | ||
|
|
||
| * **If they match:** npm installs the exact versions specified in `package-lock.json`, ensuring reproducible builds across environments. This is similar to `npm ci` but also updates `package-lock.json` if needed. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems to contradict itself, it does not install the exact versions in package-lock if the package-lock needs to be updated.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for catching that! You're absolutely right - that was contradictory. I've updated the text to remove the confusing statement about updating package-lock.json from the "If they match" scenario, since that's already covered in the "If they don't match" case. The text now simply says npm "uses the versions specified in package-lock.json" without the contradictory language.
11a4332 to
610564a
Compare
|
|
||
| * **If they match:** npm uses the versions specified in `package-lock.json` to ensure reproducible builds across environments. | ||
|
|
||
| * **If they don't match:** If you've modified `package.json` so that the version ranges no longer match what's in `package-lock.json`, npm treats it as if you ran `npm install <package>@<new-version>` for the changed packages. It will update `package-lock.json` with the new resolved versions that satisfy the updated `package.json` ranges. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We may need to explain what "in sync" means. There are two ways the file can be out of sync. If I have a package.json that says semver: ^7.0.0 and I have [email protected] in my tree, but then manually change package.json to have [email protected], when I next run npm install the only change to my lockfile will be the metadata in it that mirrors the package.json
[email protected] /Users/wraithgar/Development/scratch/lock
└── [email protected]
~/D/s/lock (main|✔) $ npm pkg get dependencies.semver
"^7.0.0"
~/D/s/lock (main|✔) $ npm pkg set dependencies.semver='^7.1.0'
~/D/s/lock (main|✚1) $ npm i
up to date in 1s
~/D/s/lock (main|✚2) $ git diff
diff --git a/package-lock.json b/package-lock.json
index ad48b26..1e047f7 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -9,7 +9,7 @@
"version": "1.0.0",
"license": "ISC",
"dependencies": {
- "semver": "^7.7.3"
+ "semver": "^7.1.0"
}
},
"node_modules/semver": {
diff --git a/package.json b/package.json
index 279765d..df1e3f3 100644
--- a/package.json
+++ b/package.json
@@ -11,6 +11,6 @@
"license": "ISC",
"type": "commonjs",
"dependencies": {
- "semver": "^7.0.0"
+ "semver": "^7.1.0"
}
}So the npm install <package>@<new-version> isn't wholly correct, as that would have also changed the package.json to have the new version as the new baseline for the version range.
~/D/s/lock (main|✚2) $ npm i semver@latest
up to date in 1s
~/D/s/lock (main|✚1) $ git diff
diff --git a/package.json b/package.json
index 279765d..76daf15 100644
--- a/package.json
+++ b/package.json
@@ -11,6 +11,6 @@
"license": "ISC",
"type": "commonjs",
"dependencies": {
- "semver": "^7.0.0"
+ "semver": "^7.7.3"
}
}The other way of course is if you change package.json to have a range outside of what's currently set there. If I were to change semver from "^6" to "^7" then it would be closer to as if you ran npm install package@new-version but it still wouldn't change the entry in package.json.
the TLDR is we may want to avoid an "as if" and have a little more direct (yet succinct) explanation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're absolutely right - I've removed the misleading "as if" analogy and provided a more direct explanation. The updated text now clarifies what "in sync" means (when lockfile versions satisfy package.json ranges) and explains the actual behavior: npm resolves new versions when ranges conflict and updates the lockfile accordingly. I also added the nuance you mentioned about metadata-only updates when changing ranges within the same major version (like ^7.0.0 to ^7.1.0). Thanks for the detailed examples!
| * **If they don't match:** If you've modified `package.json` so that the version ranges no longer match what's in `package-lock.json`, npm treats it as if you ran `npm install <package>@<new-version>` for the changed packages. It will update `package-lock.json` with the new resolved versions that satisfy the updated `package.json` ranges. | ||
|
|
||
| In essence, `package-lock.json` locks your dependencies to specific versions, but `package.json` is the source of truth for acceptable version ranges. When they agree, the lockfile wins. When they conflict, `package.json` wins and the lockfile is updated. | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We probably want to explain the way to NOT have npm change these files:
"If you want to install packages and ensure that these files match, and that npm will not change your package.json, consider running npm ci"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great suggestion! I've added a paragraph at the end of the section recommending npm ci for users who want to ensure strict synchronization without npm modifying package.json. This provides a clear path for those who need that behavior.
Adds documentation explaining how npm install handles the interaction between package.json and package-lock.json: - Clarifies when lockfile versions are used (when they satisfy package.json ranges) - Explains when lockfile is updated (when ranges conflict) - Notes that metadata-only updates occur for minor range changes - Adds npm ci reference for strict sync without modifications Closes npm#4866
99188a7 to
e2030e7
Compare
|
I re-read this after having not seen it for a few days and it read very very well. Thanks for working through this. |
Description
This PR adds documentation explaining how
npm installbehaves with respect topackage.jsonandpackage-lock.json, a common source of confusion for npm users.Changes
npm installusespackage-lock.json" to thenpm installdocumentationpackage.jsonandpackage-lock.jsonare in sync: exact versions from lockfile are installedpackage.jsonwins andpackage-lock.jsonis updatedpackage.jsonis the source of truth for version ranges, whilepackage-lock.jsonlocks to specific versionsnpm cibehaviorContext
The npm install documentation previously didn't explain how it handles the interaction between
package.jsonandpackage-lock.json. Users were confused about when versions from the lockfile are used versus when they're updated. This PR incorporates the explanation from Kat Marchán that was referenced in the issue to provide clear guidance.Closes #4866