What is the difference between npm-shrinkwrap.json and package-lock.json?
Asked Answered
P

4

208

With the release of npm@5, it will now write a package-lock.json unless a npm-shrinkwrap.json already exists.

I installed npm@5 globally via:

npm install npm@5 -g

And now, if a npm-shrinkwrap.json is found during:

npm install

a warning will be printed:

npm WARN read-shrinkwrap This version of npm
is compatible with lockfileVersion@1,
but npm-shrinkwrap.json was generated for lockfileVersion@0.
I'll try to do my best with it!

So my take-away is that I should replace the shrinkwrap with the package-lock.json.

Yet why is there a new format for it? What can the package-lock.json do that the npm-shrinkwrap.json cannot?

Porett answered 30/5, 2017 at 9:19 Comment(0)
C
233

The files have exactly the same content, but there are a handful of differences in how npm handles them, most of which are noted on the docs pages for package-lock.json and npm-shrinkwrap.json:

  • package-lock.json is never published to npm, whereas npm-shrinkwrap is by default
  • package-lock.json files that are not in the top-level package are ignored, but shrinkwrap files belonging to dependencies are respected
  • npm-shrinkwrap.json is backwards-compatible with npm versions 2, 3, and 4, whereas package-lock.json is only recognized by npm 5+

You can convert an existing package-lock.json to an npm-shrinkwrap.json by running npm shrinkwrap.

Thus:

  • If you are not publishing your package to npm, the choice between these two files is of little consequence. You may wish to use package-lock.json because it is the default and its name is clearer to npm beginners; alternatively, you may wish to use npm-shrinkwrap.json for backwards compatibility with npm 2-4 if it is difficult for you to ensure everyone on your development team is on npm 5+. (Note that npm 5 was released on 25th May 2017; backwards compatibility will become less and less important the further we get from that date, as most people will eventually upgrade.)

  • If you are publishing your package to npm, you have a choice between:

    1. using a package-lock.json to record exactly which versions of dependencies you installed, but allowing people installing your package to use any version of the dependencies that is compatible with the version ranges dictated by your package.json, or
    2. using an npm-shrinkwrap.json to guarantee that everyone who installs your package gets exactly the same version of all dependencies


    The official view described in the docs is that option 1 should be used for libraries (presumably in order to reduce the amount of package duplication caused when lots of a package's dependencies all depend on slightly different versions of the same secondary dependency), but that option 2 might be reasonable for executables that are going to be installed globally.

Chorography answered 9/9, 2017 at 16:3 Comment(11)
+1 - can you clarify your second bullet point though? What's the distinction between that behaviour and having an npm-shrinkwrap?Prototrophic
@Prototrophic the second bullet won't matter in practice unless you're doing something weird. Basically, it just says that if a library somehow did publish a package-lock.json (which isn't possible), then if you were to install that library as a dependency of some other package, the library's package-lock.json would be ignored by NPM. However, if a library publishes an npm-shrinkwrap.json, and you install the library as a dependency, then you will also install as secondary dependencies the exact versions of all dependencies specified in the library's npm-shrinkwrap.json.Chorography
Can you please add that npm ci exists to insure the installation of the package-lock.json as read-only. (npm install mutates the package-lock.json causing confusion and potential bugs and does not take advantage of the package-lock.json per se.)Porett
@Porett I don't think there's any difference between how npm ci handles npm-shrinkwrap.json and package-lock.json - what's its relevance to this question about the difference between the two files? Also, after reading around: I think that "npm install ... does not take advantage of the package-lock.json" has been false since npm 5.4 - I believe npm install now respects your package-lock unless it's outright incompatible with your package.json, in which case the latter will take precedence. (But I've been out of the JavaScript world for a bit - am I missing something?)Chorography
Mark how can I prevent npm from publishing shrinkwrap? You mentioned by default it does, which is what I am experiencing. And I don't want the shrinkwrap to be included during "npm publish" step. ThanksOphthalmitis
@Mark Amery unfortunately npm install still install the latest version available of a dependency even if the version in package.json are "solid", I mean don't have ^ or ~(that as long I know should indicate to look for the version up if possible), I referring to semantic versioning docs.npmjs.com/about-semantic-versioningBlaze
@CarmineTambascia No, that isn't true. You can test it easily: create a folder, run npm init in it, add "dependencies": {"lodash": "1.0.0"} to package.json, run npm install, and look in the generated package-lock.json. You will get Lodash 1.0.0 - not the latest version.Chorography
@Mark Amery if there is a specific version of course. But if the version is with semantic versioning then depending on the versioning is been installed the latest or also if that version is been updated in term of api. Indeed otherwise wouldn't been introduced. But somehow I wasn't correct, its try to install also latest version of peer dependecies indeed one can be now avoid that with legacy-peer-depsBlaze
@CarmineTambascia I'm confused - now you say that "of course" if you specify "a specific version" you get it, but earlier (in your August 30th comment) you were saying you "still install the latest version ... even if" you "don't have ^ or ~", i.e. if you don't use "semantic versioning". If you weren't saying you get the latest version even with a dependency declaration like "lodash": "1.0.0", what were you saying?Chorography
Why is option 2 better for global packages?Complainant
@Complainant the upside of option 2 (for any kind of package) is that when you install version X of the package you are absolutely guaranteed to get all the same sub-dependency versions (which reduces the risk of bugs or behaviour differences caused by getting different versions of subdependencies to what the package's author tested it with). It's only recommended for executable packages that are meant to be installed globally because in any other context there's a big downside to option 2 (it will tend to increase the build size of packages that depend on you), but not for global executables.Chorography
K
30

Explanation from NPM Developer:

The idea is definitely for package-lock.json to be the Latest and Greatest in shrinkwrap technology, and npm-shrinkwrap.json to be reserved for those precious few folks out there who care very much about their libraries having an exact node_modules -- and for people who want CI using npm@>=2 to install a particular tree without having to bump its npm version.

The new lockfile ("package-lock.json") shares basically all of the same code, the exact same format as npm-shrinkwrap (you can rename them between one another!). It's also something the community seems to understand: "it has a lockfile" seems to click so much faster with people. Finally, having a new file meant that we could have relatively low-risk backwards-compat with shrinkwrap without having to do weird things like allow-publication mentioned in the parent post.

Karlenekarlens answered 2/6, 2017 at 8:10 Comment(7)
I still am not clear on the difference. If npm-shrinkwrap is for exact node_modules....I assume package-lock.json is locking less than exact? And if so, what is not locking that npm-shrinkwrap is locking?Bozarth
you got it wrong @dman. package-lock is the new version of npm-shrinkwrap. package-lock is opt-out (so you have to remove the feature because it's default enabled), npm-shrinkwrap is opt-in (so you have to enable it because it's not included my default). the reason why they introduced package-lock is that 1. user now have a saver way to deal with dependencies because it's enabled by default and 2. the name implies what it is in oposite to "shrinkwrap". npm-shrinkwrap had some special dependency-behavior settings what package-lock doesn't have now. npm-shrinkwrap is now obsolete.Karlenekarlens
this is incorrect. By saying that package-lock is the new version of npm-shrinkwrap, you are saying it is a replacement. npm-shrinkwrap is not deprecated and has differences with package-lock.json. Furthermore, package-lock.json has a bug while npm-shrinkwrap does not... thus emphasizing more so they are not the same code.Bozarth
Also package-lock.json is intrusive. So it can easily cause scm conflicts if you call "npm i" while shrinkwrap should be explicitly generated and will not cause conflicts on ci servers. Yes, I can be wrong here.Altogether
@Bozarth "package-lock.json has a bug while npm-shrinkwrap does not" - no it doesn't. There's no indication of that in the issue you've linked to; it doesn't even mention npm-shrinkwrap. As I note in my answer, converting a package-lock.json to an npm-shrinkwrap.json is literally just done by renaming the file; they are "the same code".Chorography
after so many reading, I had to have exact same dependecies of a project pass to another one, then I went for npm ci as I have read. Unfortunately I ended-up with an empty node_modules, but not a new one. Of course running npm i,with package.json with non depdencies have ~ or ^ thus indicating not to look for update if existing(but I may be wrong on this) a new modified package-lock.json.Blaze
Of course this wasn't what I want as I have some legacy dependecies thatbfor the sake of development I want to keep. The only solution I found was simply to remove again node_module and copy manully the package-lock.json from the other project and run npm install. Someone could tell me if this at the moment achievable via command line and what the step to take?Blaze
O
14

I think the idea was to have --save and shrinkwrap happen by default but avoid any potential issues with a shrinkwrap happening where it wasn't wanted. So, they just gave it a new file name to avoid any conflicts. Someone from npm explained it more thoroughly here:

https://www.reddit.com/r/javascript/comments/6dgnnq/npm_v500_released_save_by_default_lockfile_better/di3mjuk/

The relevant quote:

npm publishes most files in your source directory by default, and people have been publishing shrinkwraps for years. We didn't want to break compatibility. With --save and shrinkwrap by default, there was a great risk of it accidentally making it in and propagating through the registry, and basically render our ability to update deps and dedupe... null.

So we chose a new name. And we chose a new name kind of all of a sudden. The new lockfile shares basically all of the same code, the exact same format

Ornstead answered 30/5, 2017 at 23:22 Comment(0)
S
7

package-lock.json versions are guaranteed with only npm ci (since npm install overwrites package-lock.json if there is a conflict with package.json).

npm-shrinkwrap.json versions are guaranteed with both npm ci and npm install.

Spue answered 5/8, 2021 at 2:21 Comment(2)
-1; I just checked and this isn't true, at least for npm 10.2.0. Quick test: in a new folder, run npm init --yes && npm install lodash && npm shrinkwrap. Now, in package.json, modify "lodash": "^4.17.21" (or whatever later version you see, if you are doing this in the future) to say "lodash": "3.0.0". Now run npm install; observe the "changed 1 package" message in the output. Check your npm-shrinkwrap.json and you will see it has been updated to specify version 3.0.0 of Lodash, not whatever got installed before.Chorography
(I'm not really sure how you'd be meant to work with an npm-shrinkwrap file if it did work the way this answer describes. What would the workflow for updating a dependency version be if npm install didn't write to the shrinkwrap file? Updating your lock file as you change your dependencies is a necessary part of development and if your answer were accurate that necessary behaviour would simply not be supported when using a Shrinkwrap file.)Chorography

© 2022 - 2024 — McMap. All rights reserved.