Rails upgrades without a feature freeze
A Rails upgrade doesn’t need a long-lived branch or a month where nobody ships features. I dual-boot the app on the current and next Rails version, burn down deprecations on main in small pull requests, and switch over when the test suite is green on both. Your team keeps shipping the whole time.
I built the Rails stacks behind Varsity Vibe (710,000 users) and MyPerks. The upgrade process below is unglamorous, and that’s the point.
Why upgrade branches fail
The classic approach: someone creates a rails-7 branch, works on it for six weeks, and spends the last two resolving merge conflicts with everything the rest of the team shipped. Then it goes out in one big deploy, and every bug from the upgrade lands at once.
Dual-booting fixes this. The upgrade work merges to main continuously, guarded by a flag that says which Rails version is loaded. There’s never a branch to rebase.
How I run a Ruby on Rails upgrade
- Audit the gems. bundle outdated, plus a check of every gem’s Rails compatibility and maintenance status. Gems that pin an old Rails or are abandoned get upgraded, replaced or removed first. bundler-audit flags known CVEs while we’re there.
- Sequence the Ruby upgrade. Each Rails version has a minimum Ruby version – Rails 7.2 needs Ruby 3.1 and Rails 8.0 needs 3.2, for example. Ruby usually goes first, and the jump to Ruby 3.0 (keyword argument separation) is the one that breaks the most code.
- Set up dual-booting. A Gemfile.next and lockfile using next_rails or Shopify’s bootboot. CI runs the full suite on both versions; production stays on the current one.
- Burn down deprecations. Set config.active_support.deprecation to raise in test, track the remaining warnings with next_rails’ deprecation tracker, and fix them in small pull requests on main. The count goes on a chart so everyone can see it fall.
- One minor version at a time. 6.1 to 7.0 to 7.1 to 7.2 to 8.0 to 8.1. Each hop has its own upgrade guide and its own new_framework_defaults file. Skipping hops means losing that guidance.
- Flip framework defaults individually. After bin/rails app:update, enable each new default in the generated initializer one by one, deploy, watch, and only then bump config.load_defaults.
- Cut over gradually. Deploy the next version to one canary instance or a small share of traffic, compare error rates and response times, then roll out fully. Rollback is a redeploy.
What usually breaks in a Rails 7 upgrade
- Autoloading. Rails 7 removed the classic autoloader, so anything that relied on it has to work under Zeitwerk. bin/rails zeitwerk:check finds the problems.
- Asset pipeline changes. Sprockets, Webpacker, jsbundling and importmaps each have a different migration path. Webpacker apps need the most planning.
- Encrypted and signed cookies, especially the Rails 7.0 change of the key generator digest from SHA-1 to SHA-256 that need a rotation step to avoid logging everyone out.
- Monkey patches to Rails internals in config/initializers – the most common source of mysterious failures after any upgrade.
What a Rails 8 upgrade adds
Rails 8 is a smaller jump from 7.2 than 7.0 was from 6.1. It brings Solid Queue, Solid Cache and Solid Cable as database-backed defaults, Propshaft as the default asset pipeline, Kamal for deploys, and a built-in authentication generator. None of those are mandatory for existing apps. Upgrade first, then decide separately whether to adopt them – mixing the two makes it harder to tell what caused a regression.
For which Rails versions still get security fixes, check the official Rails maintenance policy rather than a blog post, because it changes as new versions ship.
When an upgrade is part of something bigger
If the app is many versions behind, poorly tested and the team is afraid to touch it, the upgrade is one part of a wider legacy modernization job. If you mostly need senior Rails judgement beyond the version bump, see Ruby on Rails consulting. And the payoff of a current framework is easier ongoing technical debt reduction.
Questions
How long does a Rails upgrade take?
It depends on how many versions you’re jumping, the test coverage and the gems. A well-tested app one version behind can take days. An app several versions behind with abandoned gems takes weeks of incremental work, but features keep shipping throughout because of dual-booting.
Can we skip Rails versions when upgrading?
You can, but you shouldn’t. Each minor version has its own deprecations, upgrade guide and framework defaults. Going one hop at a time keeps each change small and lets you use the deprecation warnings as a to-do list.
Should we upgrade Ruby or Rails first?
Usually Ruby, to at least the minimum the target Rails version requires. Older Rails versions often support newer Ruby versions, so you can upgrade Ruby while still on the old Rails, then move Rails. Check each version’s compatibility before planning.
What is dual-booting in Rails?
Dual-booting means the app can boot on two Rails versions from the same branch, using a second Gemfile lockfile chosen by an environment variable. Tools like next_rails and bootboot set it up. CI tests both, so upgrade work merges continuously.
Rails app stuck a few versions behind?
Tell me your Rails and Ruby versions. In a two-week sprint I’ll set up dual-booting, audit the gems and ship the first deprecation fixes.
GMT+2 · Full EU overlap · US East mornings