Let's say you are running Cypress on Continuous Integration service, like Circle or GitHub Actions. You probably want to cache NPM modules and Cypress binary - these things are large. Let's leave the NPM cache alone - you can read the post Do Not Let NPM Cache Snowball on CI on how to avoid the cache growing out of the control. Instead let's look at the Cypress binary cache.
Note: you can find the source code for this blog post in the repository bahmutov/cypress-snowball.
We start with installing Cypress v4.12.1 and then write the circle.yml
file
1 | version: 2.1 |
The job passes.
Now let's configure caching following Circle caching docs. Before installing NPM dependencies, we need to restore the previous cache. By copying the Circle docs we get the following:
1 | version: 2.1 |
The build runs. It does not find a previous cache to restore, first trying the exact match "v1-deps-package-lock hash", then trying just the prefix "v1-deps-".
Cypress v4.12.0 is installed, and is visible using cypress cache list
command. The two folders are then stored under the key "prefix + package-lock hash".
Now let's upgrade Cypress dependency to the currently latest version v5.6.0
1 | $ npm i -D [email protected] |
This changes the package lock file, and when we push the commit we observe the following on Circle.
Hmm. We have a problem. The exact key to restore the cache was not found, because the package lock file has changed. But the previous cache did match the second restore cache key with just the prefix "v1-deps-". Thus we have restored Cypress v4.12.1 binary, installed Cypress v5.6.0 (you can see both of them in the list), and then saved both in the new cache. The cache was 171MB with just Cypress v4.12.1 and is probably much larger now with two Cypress binaries.
Let's install a different Cypress version, like v5.4.0 and trigger the CI build.
Wow, the cached folder is really growing. Notice the time it takes to save the updated cache with three Cypress binaries: 1 minute and 19 seconds. Do you know how long it should take to cache just a single Cypress version? 20 seconds.
It takes a lot of extra time to restore and save those extra versions of Cypress, doesn't it.
We ourselves got this wrong in GitHub Actions, see issue #219.
Advice
So what should we do to avoid snowballing Cypress binary cache? Use the exact restore key version and do not use the fallback prefix key.
1 | version: 2.1 |
Advice: use Cypress orb
When running Cypress tests on CircleCI, you have an even better option. You can use the official Cypress Orb to dramatically simplify installing, caching, and running Cypress tests.
For example to just install NPM dependencies with caching, including Cypress binary, one could write the following circle.yml
file from branch use-cypress-orb:
1 | version: 2.1 |
Note: typically you would use cypress/run
job, here cypress/install
is used for clarity. They work the same in terms of installation and caching.
The first run with Cypress v5.5.0 has a single binary version to cache.
After installing a different version of Cypress, the CI runs again. It works correctly - only a single new version of Cypress is carried.
Happy caching!