Caching your Node modules in Azure DevOps

Riccardo Corradin on 07 January 2022

How can you make your builds complete faster so that you can build more often and have earlier feedback?
You could do this by caching your node modules in Azure DevOps. I’ll explain how to do this in this blog post.

Creating a build pipeline in Azure DevOps for a Node.js based application is straightforward. You only need a few lines of code to achieve this. You’ll likely add tasks, such as linting, running tests, and maybe even more. As a result, the pipeline will take longer to complete with each added task. Let’s start speeding things up using caching.

You can find the repository for node modules caching in Azure DevOps here.

 Suppose the pipeline YAML file looks as follows:

The first step is to install all dependencies. The second step needs these dependencies in order to start the build. In this example, I used a React application. However, any application that needs NPM packages will profit from the caching solution.

The results are as follows:

Azure DevOps pipeline run results without node caching

A build time of under a minute is not bad at all, but we can do better.

Add caching

The azure-pipelines.yml in the repository will be changed to the following:

The Cache task takes different inputs. There is a key input, which can be a normal string value or in this case a file path. The contents of package-lock.json will be hashed and produce a dynamic cache key. This means that if the contents of the package-lock.json file change, a new key will be generated.

The second input is the path of the folder that needs to be cached. NPM uses ~/.npm on POSIX and %LocalAppData%\npm-cache on Windows machines. On the Ubuntu image, I haven’t found a way to access ~/.npm, so instead, I set the .npm folder in the workspace as a cache location. This can be done by adding the cache argument to the npm ci command. Next to this, it is recommended to set your cache folder, since it will keep running when you switch to a Windows agent for example.

After committing the YAML file and waiting for the build to complete, let’s look at the results:

Azure DevOps pipeline first run results with node caching

This run takes longer because the cache needs to be saved. I.e.: The cache key has not been found, so there is a cache miss.

Let’s run the pipeline again and check the results:

Azure DevOps pipeline subsequent run with node caching

It still takes somewhat longer, but now the cache is downloaded and the npm ci command will take the node modules it needs from the .npm folder. The “NPM install dependencies” task went from 28 to 10 seconds.

Depending on the number of tasks in your build pipeline your mileage may vary. I managed to improve the build time 5m 29s to 3m 22s minutes at my client.

 

Conclusion

Node modules caching in Azure DevOps will reduce your pipeline run duration when your solution relies on node packages. In my opinion, you should start doing node module caching when creating a pipeline. I believe the performance benefits will outweigh the time needed to implement this.

 

Let me know what you think

Any comments are more than welcome! Drop me a message through LinkedIn or Twitter @rscorradin.