Resources · Engineering

Rails upgrade or Rails rebuild? A guide for teams stuck on Rails 4, 5 or 6

In short

Teams on Rails 4, 5 or 6 face a choice between upgrading in place and replacing the application workflow by workflow. An upgrade is cheaper for a small, well-tested, slow-changing app with few integrations. Incremental replacement wins when the app is large, poorly tested, changing often or deeply integrated. Four measurable variables decide it.

Abstract illustration: a staircase of versions beside a curved alternative path

If your core application runs on Rails 4, 5 or 6, you already know the facts. Security patches stopped years ago. Every feature request starts with a conversation about what else will break. The question isn't whether to act but which way: upgrade in place, or replace the application piece by piece.

Both can be the wrong answer. We've done upgrades that took three weeks and upgrades that quietly swallowed a year, and we've seen incremental rebuilds started on applications that a disciplined upgrade would have fixed for a fraction of the cost.

The short version: an upgrade buys time on a supported platform without changing how the system works. Incremental replacement buys the ability to change the system, workflow by workflow, while it keeps running. The choice depends on four variables you can measure this week: app size, test coverage, change frequency and integration count. Let's start with the support calendar.

Where the Rails support calendar stands today

The Rails maintenance policy has been simple since 7.2: each minor release gets one year of bug fixes and two years of security fixes. At the time of writing (October 2026) only two series receive security fixes: Rails 8.1, until October 10, 2027, and Rails 8.0, until November 7, 2026. Everything else is out of support (endoflife.date keeps the full list):

Ruby moves on the same kind of clock, with roughly three years and three months of support per release. Ruby 3.2 reached end of life on March 31, 2026 and 3.3 follows on March 31, 2027. Rails 8 requires Ruby 3.2 or newer. So a Rails 5.2 application on Ruby 2.6 is seven Rails minor versions and six or seven Ruby versions from a supported release, and the two ladders have to be climbed together. The gap grows while you decide, since Rails aims to ship a new minor every six months.

What an in-place upgrade really costs

Experienced teams upgrade one minor version at a time, as the Rails team recommends. Each hop involves four kinds of work.

Gems

Every dependency has to support the next Rails and Ruby version. Some need a major version bump with its own breaking changes; some are abandoned and have to be replaced or forked. In the 2024 Rails Community Survey of 2,709 developers, 12% of those whose applications weren't all current gave third-party dependencies as the reason. In our experience the gem audit is where the first honest estimate appears.

Ruby versions

Ruby 3.0 separated positional and keyword arguments and broke a great deal of working code; later releases removed default gems. These changes land in your code and in every gem, and only the test suite, or production, finds them.

Deprecated APIs and framework defaults

Each Rails minor deprecates something and changes defaults, from autoloading to cookie serialization. The warnings from one version are the breakages in the next, which is why skipping versions saves nothing. GitHub's upgrade from Rails 3.2 to 5.2 took a year and a half and grew from one full-time engineer to four, even with the application dual-booting in two Rails versions so deploys could continue.

Missing tests

Michael Feathers defined legacy code as code without tests, and an upgrade is where that definition bites. Without a suite, every hop needs manual regression testing of the whole application. FastRuby, which has published data on more than 100 upgrade projects, reports that as coverage goes down "the level of uncertainty goes up and so does the potential cost".

Their 2023 figures for a vendor-run upgrade, per major jump: Rails 4.2 to 5.2, $55,000 to $175,000; 5.2 to 6.1, $40,000 to $120,000; 6.1 to 7.0, $60,000 to $135,000. Add them up and a 4.2 application is looking at roughly $155,000 to $430,000 to reach 7.0, before the four minor versions released since. In-house, the same effort shows up as a roadmap that stops. And you end with the same application, same undocumented rules, on a supported version.

When "just upgrade" is the right answer

The upgrade route wins when:

An application like that is weeks of work, not quarters. Replacement machinery would cost more than the upgrade and deliver nothing the business asked for. Upgrade it and move on. GitHub's advice holds: the closer you stay to current, the cheaper every future hop is.

When incremental replacement is cheaper, and when it isn't

Incremental replacement is Martin Fowler's strangler fig applied to one application: a proxy in front of the current system, selected workflows rebuilt alongside it, traffic moved a workflow or a customer cohort at a time, and the old code retired when nothing routes to it. It costs more per workflow than an upgrade, because new code costs more than fixes. It's cheaper overall in two situations.

When the upgrade costs most of what new code would. On a large 4.2 application with low coverage and a dozen abandoned gems, "upgrade" means writing the tests, replacing the gems and relearning the rules anyway. You pay most of the price of new code and end up with old code.

When change frequency is the problem, not the version number. If the business is waiting on pricing changes or a self-serve plan, an upgrade delivers neither. Replacing the workflow that blocks the priority delivers the priority and retires part of the legacy. In the same survey, 28% gave "not considered a priority" as their reason; tying the work to a business initiative is one way to change that.

When it isn't cheaper: the small, well-tested, slow-changing application above, and any application where every new workflow would keep sharing the same forty tables, because data transition then dominates the work. Replacement also doesn't remove the security exposure of the part still on the old version. You need a plan for it, usually to keep it patched behind the proxy and retire it workflow by workflow.

A decision table, and a worked example

Score each dimension against our rough thresholds. Three or four in one column is a clear answer. A split means a hybrid: upgrade the stable core, replace the workflows that change.

A publisher's subscription system came to us on Rails 4.2 and Ruby 2.3: around 90 models, coverage in the twenties, 14 gems with no release in five years, and six integrations. The internal estimate for a full upgrade was nine to twelve months with two engineers, and the pricing change marketing wanted would have waited behind it.

All four dimensions pointed the same way, so we didn't upgrade first. We put a proxy in front, rebuilt the plan-and-pricing workflow against the behavior observed in production, reconciled invoice totals against the old system for a month, and moved subscribers over by cohort. The pricing change shipped while the old system kept serving everything else. With 85% coverage and two integrations, we'd have upgraded it and said so.

Where Fabrica stands

Fabrica's CLEAR method is built for the replacement column of that table, starting with Rails. Capture records what the running application does, Lock turns that into a System Specification the owners approve, Engineer rebuilds the scoped workflow, Attest tests both implementations side by side, and Release moves a cohort with acceptance criteria and rollback. The assessment produces the gem, coverage and integration evidence above, and its recommendation may be to upgrade rather than rebuild. What your engineers can check is on the engineering page.

Decide on evidence, then move

The expensive outcome is neither route. It's another year on Rails 5 while the decision waits. Measure the four variables, price the upgrade per minor version, and compare that with replacing the one workflow the business is waiting on. Whichever column wins, put a date on the first production change and a CI job against the next Rails version, so you never fall this far behind again.

Questions to ask before you choose

Keep reading

Related

Which priority is your system holding up?

Tell us about it on a 30-minute call. We'll suggest a first scope and what a technical review would need to confirm.

Book a 30-minute call