In this article, I'll show how to set up & use npm caching in GitLab CI.
Example package
For this article, I created a project with create-react-app. It's installing quite a few dependencies, and we need enough of them to see the positive impact of caching on the run time.
Baseline
The baseline CI configuration is as follow:
image: node:16
stages:
- build
build:
stage: build
script:
- npm ci
To simplify, I only run the installation with npm ci
. In this way, the complete time of the job is setting up the stage for the build itself - getting the node:16
image to the agent & dependencies for npm.
I run the build with this configuration 3 times, and every time the total time was 1 minute 41 seconds in our baseline.
Adding cache
For enabling the cache, the configuration gets a bit more complicated
image: node:16
stages:
- build
cache:
key: npm
policy: pull-push
paths:
- .npm/
build:
stage: build
script:
- npm ci --cache .npm --prefer-offline
Where:
-
cache:key: npm
- I want to share this cache across different CI runs. In the documentation they show an example of how to limit cache use only to the current CI run - in the case of npm dependencies, they are safe to reuse between CI runs, especially because npm still will make sure to install them in the correct version. -
policy: pull-push
- setting the default cache policy explicitly - it will load the cache before & upload it after the job run. If we were adding more jobs, we could save few seconds making sure we onlypull-push
from the very first one, and all the others will onlypull
-
paths: .npm/
- a folder we picked for keeping the cache. If you use git during your builds (to create commits, or to rungit describe
), it would make sense to add it to your.gitingore
-
npm ci --cache .npm --prefer-offline
- first we tell npm where to find the cache with--cache .npm
, second--prefer-offline
disables online checks of cached packages.
Cold cache
The first run after setting up the cache took 1 minute 48 seconds. The 7s we lost in comparison to baseline is downloading & uploading the cache files.
Warm cache
I run the job 3 times & always got not more than 1 minute 6 seconds.
So we saved 35s of the installation in this simple use case - in cases of more complex apps, the time saved will get even better.
Links
You can find the complete repository here.
Summary
In this article, we have seen how to speed up the npm installation in the GitLab CI. The half a minute gain we had here, in a real-world case, will most likely appear in a few places on the critical path of our CI run.
Top comments (1)
The main limitation with this approach is that, as of now, when a build fails Gitlab-ci won't create a cache. In some situations it can be problematic. See gitlab.com/gitlab-org/gitlab/-/iss...