Conquering npm shrinkwrap (in layman’s terms)

Posted by on July 20, 2016.

We’ve all been there. You start with a simple app idea and get to work. With the vast number of packages available on npmjs.org, your dependency list begins to grow exponentially. You then hear about a neat npm CLI command called shrinkwrap.

What is it?

[Shrinkwrap] locks down the versions of a package’s dependencies so that you can control exactly which versions of each dependency will be used when your package is installed.
npmjs

Life without shrinkwrap

Because package.json often specifies only a minimum version number, another person using your package could run npm install and end up with different dependency versions than you.

For example, let’s say Developer-A runs npm i --save-dev surprise-pkg@1.0.0 and pushes his changes to Github. Package.json now reads "surprise-pkg: "^1.0.0". Developer-B comes along some time later, clones the same repo, and runs npm install. To his surprise, he notices that surprise-pkg installs version 1.9.9, even though his package.json reads the same as Developer-A’s.

Do you see why that could be a problem? Developer-A and Developer-B are now developing with different versions of surprise-pkg!

Shrinkwrap to the rescue

The scenario above can be easily resolved with npm shrinkwrap. Not without a few headaches, of course. But that’s why this was written… so you could wrap your head around the mystery of shrinkwrapping!

So, let’s backtrack. Developer-A runs npm i --save-dev surprise-pkg@1.0.0 again, but this time he runs npm shrinkwrap --dev before committing and pushing his changes to Github. Package.json still reads "surprise-pkg: "^1.0.0", but there is a new file- npm-shrinkwrap.json. If Developer-A were to dig into this file, among all of the other dependencies he would find the following:

"surprise-pkg": {
  "version": "1.0.0",
  "resolved": "https://registry.npmjs.org/surprise-pkg/-/surprise-pkg-1.0.0.tgz"
}

Now, when Developer-B comes along, clones the same repo, and runs npm install, he would find surprise-pkg@1.0.0 was installed too. Now both developers can code in harmony with the same version of surprise-pkg!

Order of operations (Installing)

It is important to understand the precedence of package.json and npm-shrinkwrap.json. Here are a few pointers:

When you run npm install
1. If npm-shrinkwrap.json exists, ONLY the dependencies specified in your shrinkwrap file will be installed.
2. Otherwise, dependencies in package.json will be installed according to the semantic version specified (like the above example).

You can also ignore an existing shrinkwrap with the --ignore-shrinkwrap flag.

CAUTION: I don’t advise you ignore shrinkwrap unless you know what you are doing.

Shrinkwrap best practices

When you are working on any repository that uses a shrinkwrap, you should follow these best practices to avoid causing you and your team shrinkwrap headaches.

  • Given there is an existing shrinkwrap file, you should always npm install before installing any new packages or updates and subsequently running npm shrinkwrap.

    Why? Since a generated shrinkwrap is based upon what is in your node_modules folder, you should always make sure that your installed node_modules match those that may have been recently updated & shrinkwrapped by others on your team.

  • Don’t forget about package.json. Whenever you install a new module, remember to --save or --save-dev.

    Why? It is possible to install a new module without saving it to package.json and still have the new version get shrinkwrapped. But then you end up with discrepancies between package.json and npm-shrinkwrap.json– a developer headache.

Leave a Reply