This simple improvement can have varying effects on the application depending on
how many Gems you require. Before you actually jump into this I would definitely
recommend having a full unit-test suite. Anytime you’re refactoring code or
changing how dependencies are loaded you want to be sure you aren’t messing
The examples from this post were performed on a Rails 3.1.3 application running
on Ruby 1.9.3 on a Mac OSX PowerBook. The Gemfile contained about 65 gems in
The first step to any performance improvement endeavor is to benchmark. It’s
also important that you perform this step more than once - this gives you a more
consistent reading as the first run can often be inflated above the average
Now let’s take a look at your application.rb and measure how much time we’re
spending loading gems.
When we run this benchmark we get an interesting result:
We’re spending about 1/3 of our time in this Bundler.require statement. The
reason for this is that Bundler is loading and executing every gem in your
Gemfile, and with 65 gems that’s a hefty portion of time spent executing code.
We can confirm this by benchmarking the two parts of Bundler.require -
Bundler::Runtime#setup and Bundler::Runtime#require. I’m going to leave out
the details, but require is the offender here, and that makes sense. Bundler
isn’t really doing anything fancy, but it is responsible for executing all those
gems you’ve collected in your Gemfile.
Here’s a simple way to improve that.
Begin with a minor gem. By that I mean a gem that is only used in one or two
files or that has minimal impact on your application. That’s usually a good
starting point because the effects are minor. Also, don’t pick a gem that rails
automatically includes anyways – that won’t work.
Check if the gem has Railties. One way to do this is to navigate to its
source code directory and search for uses of ‘Railtie’.
If you see an output then that gem uses Railties and you need to move on to
another gem for this optimization.
If you don’t see an output then the gem does not use Railties. That means it
doesn’t hook into the Rails initialization process, which in turn means that it
does not need to be required during the application boot. So, let’s take care of
that – tell bundler to not require that gem.
Find uses of that gem, and manually require the gem in those files.
Run your tests.
Run your benchmarks.
You probably won’t notice a difference form a few measly gems, but once you’re
done with the entire process you’ll be looking at a significant time
improvement. In this particular application I was able to shave 10s off each
application boot. There’s an added benefit that you now know exactly which files
are using which gems. This makes it easier to test these files in isolation and
measure the impact/use of a gem. Enjoy!