Caching RubyGems Install

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!

1 Like

Will this work for caching the entire Ruby install? Right now Circle CI doesn’t support Ruby 2.3.3, and installing Ruby adds more than 4 minutes to every single build.

I just tried this by adding opt/circleci/.rvm to cache_directories. It didn’t work because the cache is restored after Ruby is installed.

Hello!

This post is regarding caching gem packages downloaded via gem install (including bundler), but not Ruby itself – which is handled by rvm.

If you’re looking for a way to cache Ruby binaries themselves to speed up your build time for versions that aren’t included in our build image, head over here: Caching compiled Rubies with RVM

2 Likes