I just recently upgraded to npm@5. I now have a package-lock.json file with everything from package.json. I would expect that, when I run npm install
that the dependency versions would be pulled from the lock file to determine what should be installed in my node_modules directory. What's strange is that it actually ends up modifying and rewriting my package-lock.json file.
For example, the lock file had typescript specified to be at version 2.1.6. Then, after the npm install
command, the version was changed to 2.4.1. That seems to defeat the whole purpose of a lock file.
What am I missing? How do I get npm to actually respect my lock file?
I've found that there will be a new version of npm 5.7.1 with the new command
npm ci
, that will install frompackage-lock.json
onlyHere is a scenario that might explain things (Verified with NPM 6.3.0)
You declare a dependency in package.json like:
Then you do,
npm install
which will generate a package-lock.json with:Few days later, a newer minor version of "depA" is released, say "1.1.0", then the following holds true:
Next, you manually update your package.json to:
Then rerun:
Update 3: As other answers point out as well, the
npm ci
command got introduced in npm 5.7.0 as additional way to achieve fast and reproducible builds in the CI context. See the documentation and npm blog for further information.Update 2: The issue to update and clarify the documentation is GitHub issue #18103.
Update 1: The behaviour that was described below got fixed in npm 5.4.2: the currently intended behaviour is outlined in GitHub issue #17979.
Original answer: The behaviour of
package-lock.json
was changed in npm 5.1.0 as discussed in issue #16866. The behaviour that you observe is apparently intended by npm as of version 5.1.0.That means that
package.json
can trumppackage-lock.json
whenever a newer version is found for a dependency inpackage.json
. If you want to pin your dependencies effectively, you now must specify the versions without a prefix, e.g., you need to write them as1.2.0
instead of~1.2.0
or^1.2.0
. Then the combination ofpackage.json
andpackage-lock.json
will yield reproducible builds. To be clear:package-lock.json
alone no longer locks the root level dependencies!Whether this design decision was good or not is arguable, there is an ongoing discussion resulting from this confusion on GitHub in issue #17979. (In my eyes it is a questionable decision; at least the name
lock
doesn't hold true any longer.)One more side note: there is also a restriction for registries that don’t support immutable packages, such as when you pull packages directly from GitHub instead of npmjs.org. See this documentation of package locks for further explanation.
Use the newly introduced
Introducing
npm ci
for faster, more reliable buildsIt appears this issue is fixed in npm v5.4.2
https://github.com/npm/npm/issues/17979
(Scroll down to the last comment in the thread)
Update
Actually fixed in 5.6.0. There was a cross platform bug in 5.4.2 that was causing the issue to still occur.
https://github.com/npm/npm/issues/18712
Update 2
See my answer here: https://stackoverflow.com/a/53680257/1611058
npm ci
is the command you should be using when installing existing projects now.In the future, you will be able to use a
--from-lock-file
(or similar) flag to install only from thepackage-lock.json
without modifying it.This will be useful for CI, etc. environments where reproducible builds are important.
See https://github.com/npm/npm/issues/18286 for tracking of the feature.