4

Today I was looking up some information about caching in Azure Pipelines combined with installing NPM packages. We use npm ci in our pipelines which can take a while. Caching might speed it up (and introduce other risks) and I want to find out if caching npm ci is a good idea in a CI/CD pipeline or not because I find a lot of conflicting information about this.

What benefit does caching have?

If I read the official documentation, the following is said:

Because npm ci deletes the node_modules folder to ensure that a consistent, repeatable set of modules is used, you should avoid caching node_modules when calling npm ci.

The thing that makes an npm ci so slow is that it has to retrieve all the node_modules. But the only conclusion I can draw from that sentence above is that we should not cache node_modules. So what is the point of enabling that cache task for npm ci if the node_modules aren't cached? My assumption is that by not caching the node_modules, you lose the speed benefit which would have been the point of caching.

Caching is dangerous, right?

npm ci provides a CLEAN install based on the package-lock.json. But if you add caching into the mix and retrieve some node_modules from the cache instead of the server, you create a risk of retrieving stale/outdated/wrong packages because cache invalidation is hard.

Based on this, caching and npm ci should never be used together, right?

Conflicting information

The previous headers tell me that I shouldn't try to make npm ci faster by using a cache in azure pipelines. But if you use your favorite search engine and search for azure pipelines cache npm, you will find lots of resources telling you exactly how to do this. Including answers from Stack overflow:

You can find many more. Why is there so much conflicting information?

Finishing up

  • Should you, or should you not, use the caching task in azure pipelines combined with npm ci. Please explain the reasons for your answer!
  • If the consensus is yes, you should, if you want to speed up your installs: what are the benefits of using caching with npm ci if you don't cache the node_modules
  • If the consensus is no, then what can we do to increase the speed of our installs?
S. ten Brinke
  • 2,557
  • 4
  • 25
  • 50

1 Answers1

2

The most important distinction to make is that caching your node_modules folder is different from caching .npm.

  • node_modules is a folder created when running npm i or npm ci. It contains uncompressed packages, based on the dependencies as defined in package-lock.json.

When you run npm ci it throws away the node_modules folder, so it can build a new dependency tree based on your package-lock and do a clean install of all included packages.

On the other hand, npm i makes a new package-lock based on version descriptions in your package.json. Then it only updates packages in your node_modules folder with versions that changed.

Both commands first check the cache whether any requested versions already exist there for installation. If the package is not found in your cache, or the cached version is invalid, it will download a new version from the registry and update the cache.

  • npm cache is what NPM uses internally to cache specific package data.

The default folder for the cache differs per OS, and the default for Linux/Mac (~/.npm) is not reachable in most CI environments.

This is why many resources redefine the cache folder via npm ci --cache .npm. This lets npm ci know to look for the cache at ./.npm instead, though any path inside the current workspace could be valid.

In order to preserve this custom folder between different CI pipelines, you can cache it again via Azure Pipelines (or whichever platform you're using).

Important: the cache you define in your pipeline must be invalidated and save a new version whenever package-lock changes, as that means npm ci will need to install new versions/packages and update its npm cache accordingly.

Note: you can also add the --prefer-offline flag in order to skip staleness checks on existing package versions to speed your pipeline up further.

Excalibaard
  • 1,903
  • 9
  • 19