As you may know, CircleCI already caches a number of dependency managers for you.
In the case of Ruby applications, this means anyone using bundler to install dependencies will automatically be cached.
However, what if you’re not using bundler? For whatever reason, maybe you only need 1 or 2 gems and not worth installing a separate library just to manage them. Especially considering that adding a dependency manager to your application can increase complexity and compound the problem.
Sticking with the package manager
If this sounds familiar, then you’ve probably already tried this approach and your circle.yml
looks like this:
dependencies:
pre:
- gem install fastlane
However, you will notice that this will re-install the gem on every build.
In the case of fastlane
this can take around 20 seconds! This is because the fastlane
gem also depends on a number of libraries including native extensions which much compile every time.
Just Cache It
Now you’re probably wondering how to cache this to speed things up.
The answer is rather simple! Cache All the Gems!!
We can use the “cache_directories” option of the configuration to do so.
So we end up with a circle.yml
that looks like this:
dependencies:
cache_directories:
- "/opt/circleci/.rvm/gems"
pre:
- gem install fastlane
Which in this case brought the “gem install” step of the build from 20 seconds to just 3 seconds.
Caveats
There are some caveats to this to be aware of.
First, if you already have a big cache, or plan on installing many gems like this – it’s better to use a dependency manager like bundler
.
This is because restoring the cache may actually take longer than just installing your dependencies from a network or existing cache.
Always measure the performance of these changes, and don’t blindly cache things without doing science!