How to upgrade a big Rails application

Why should we upgrade applications?

  • Software development issues
    • Security issues
    • Dependency hell
    • New software
    • Improved APIs
    • New features
    • Performance
  • Involving new people
    • Developers
    • Novice Developers

About upgrading applications

Upgrading an application especially a big one is a complicated task, but it shouldn’t be so. It should be easy!

It’s an opportunity to learn something new.

It’s a good chance to contribute to Open Source.

Long-running branch strategy

Long-Running Branches Considered Harmful - New Relic Blog:

Shopify’s Rails upgrade story

Shopify is one of the largest Ruby on Rails codebases in existence - Shopify Engineering Blog

RailsConf 2017: Upgrading a big application to Rails 5 by Rafael França


Upgrading Shopify to Rails 5:

Dual boot strategy

Dual boot is the process of booting your application with a different set of dependencies.


# Gemfile
gem "rails", "~> 5.2.2"
eval_gemfile "Gemfile.common"
gem 'rails', '~> 6.0.0.beta3'
eval_gemfile "Gemfile.common"
# Gemfile.common
source ""

ruby "2.6.2"

# ...
$ bundle install # Gemfile.lock
$ bundle install #
$ rails runner "p Rails.version"
$ rails runner "p Rails.version"


You need to deal with three Gemfiles and the confusion that comes with it:

Gemfile,, Gemfile.common vs. Gemfile

You need to ensure that all the lockfiles are in sync whenever a developer updates or adds a dependency:

$ bundle install # Gemfile.lock
$ bundle install #


$ bundle install # Gemfile.lock,

Bootboot is a Bundler plugin meant to help dual boot your ruby application.


  1. In your Gemfile, add this
    plugin "bootboot", "~> 0.1.2"
  2. Run bundle install
  3. Run bundle bootboot
  4. Commit the Gemfile and the Gemfile_next.lock

Dual boot: Shopify/bootboot

diff --git a/Gemfile b/Gemfile
-gem 'rails', '~> 5.2.2'
+ gem 'rails', '~> 6.0.0.beta3'
+ gem 'rails', '~> 5.2.2'
$ DEPENDENCIES_NEXT=1 bundle update rails # Gemfile_next.lock
$ rails runner "p Rails.version"
$ DEPENDENCIES_NEXT=1 rails runner "p Rails.version"

Dual boot: Make it work

$ rails test
$ DEPENDENCIES_NEXT=1 rails test
  def execute
    # ...
  def execute
    # ...

Dual boot: Rollout to production

$ RAILS_ENV=production rails server
$ DEPENDENCIES_NEXT=1 RAILS_ENV=production rails server

Upgrading GitHub to Rails 3 with Zero Downtime:

Upgrading a Rails application incrementally:

Dual boot: Gradual rollout to production

upstream myapp1 {
  server weight=99;
  server weight=1;
}$ RAILS_ENV=production rails server$ DEPENDENCIES_NEXT=1 RAILS_ENV=production rails server

If you have lots of servers in production, you can just roll out the app with the next dependencies on 1% of servers and on the 99% servers run the app with the current dependencies and gradually change the ratio.

Once you are 100% in production with the app that uses the next dependencies, then it’s time to remove all if ENV['DEPENDENCIES_NEXT'] conditions from the codebase and prepare to the next upgrade.

RailsConf 2018: Upgrading Rails at Scale by Edouard Chin


Eliminate deprecations from your codebase: