Your application has been running on Rails 6 for years. It works, it brings in revenue, but the framework is no longer maintained: no more security patches, gems that refuse to install, developers who wince at the code. Sooner or later, you have to upgrade from Rails 6 to Rails 7. The good news: it's not a risky big bang. It's a path taken in stages, where every step is tested before moving on to the next.
Here's how we go about this upgrade at Super Génial without breaking what works, and why method matters more than speed.
Why we never skip several versions at once
The temptation is real: start from Rails 6.0 and aim straight for Rails 7.1, in a single switch. That's the surest way to end up with an application that no longer boots and a pile of errors impossible to untangle. When a hundred things change at the same time, you no longer know which one caused the failure.
Rails is designed for a gradual climb. Each minor version introduces its share of deprecations: the framework warns you that a behavior is going to disappear, before actually removing it in the next version. These warnings are your roadmap. By moving forward step by step — 6.0 to 6.1, then 6.1 to 7.0, then 7.0 to 7.1 — you handle deprecations one by one, while they are still just messages in the logs, not blocking errors.
Each step follows the same ritual: you update the version, run rails app:update to regenerate the configuration files, read each proposed diff, and only move on to the next once the test suite is entirely green. A step can take an hour or a day. But you always know exactly where you stand.
The test safety net: the condition before touching any code
This is the non-negotiable point. You don't migrate an application without a test safety net. Without it, every change is a gamble: you modify the configuration, the app seems to run, and three weeks later a customer discovers that the checkout flow has been broken since the migration.
Automated tests turn that gamble into certainty. Before each step, they're green. Afterwards, if they stay green, you know the observable behavior hasn't changed. If they turn red, they pinpoint the regression precisely — in the right file, on the right line.
Many legacy applications have no tests at all, or so few that they cover nothing useful. In that case, we don't just charge ahead anyway: we first put regression tests in place on the critical paths — login, payment, key forms, the pages that bring in money. Not exhaustive coverage, but a solid net where a failure would be costly. This preliminary work is often what separates a calm migration from a nightmare. We build it systematically into our takeover and maintenance engagements.
The notable changes between Rails 6 and Rails 7
Three shifts call for particular attention during this upgrade.
Zeitwerk, the class loading. Rails 6 still tolerated the old loading mode (classic). Rails 7 mandates Zeitwerk, which requires a strict match between your file names and your class names. The slightest discrepancy — an API where Zeitwerk expects Api — blocks the boot. That's exactly why we enable Zeitwerk as early as the 6.x step, while it's still optional: we sort the problem out while it isn't yet fatal.
Turbolinks becomes Turbo. This is the most visible change on the front end. Rails 7 replaces Turbolinks with Turbo, the central building block of Hotwire. Turbo doesn't just speed up navigation: it introduces Turbo Frames and Turbo Streams, a new way to update parts of a page without custom JavaScript. The turbolinks to turbo migration isn't a simple rename: some existing JavaScript behaviors have to be rewritten, and each interaction needs to be checked. We move page by page, never blindly.
Encrypted credentials. Rails 7 consolidates secret management per environment. If your application is still dragging around old secrets.yml files or scattered variables, this is the moment to tidy everything away into encrypted credentials, versionable without exposing a single password.
A migration is not a rewrite
The classic trap, when you open the hood of an old application, is wanting to redo everything along the way: the design, the architecture, that part of the code you find ugly. You then blend two projects together, and you lose the one thing that makes a migration safe: the ability to say "nothing changed except the Rails version."
The discipline is to migrate first, refactor later. A step should change only what the version bump requires. The rest — the improvements, the new features — comes afterwards, on a codebase that is up to date and maintained again.
This is exactly the kind of work we carry out at a fixed price: a clear diagnosis, a step-by-step path, a test safety net put in place where it's missing, and an application that runs again on a supported version. If your app is stuck on Rails 6, let's talk — start with our maintenance and upgrade offer, or take a look at our pricing and other resources.