← Blog

From Legacy Rails 5 to 7: A Migration Story (What Broke, What We’d Repeat)

2 min read

From Legacy Rails 5 to 7: A Migration Story (What Broke, What We’d Repeat)

Upgrading Rails is not a task—it’s a system-level change that exposes everything your app has been hiding.

In one of our production systems, we migrated a long-lived Rails 5 application to Rails 7.

This wasn’t just a version bump.
It was a deep dive into dependencies, architecture, and assumptions we had made over the years.

Here’s what actually happened—what broke, what worked, and what I’d do differently.


🔍 Why This Migration Was Necessary

Over time, we started facing:

  • Slower performance
  • Outdated gems
  • Security concerns
  • Difficulty onboarding new developers

👉 Staying on old Rails versions becomes a liability.


⚠️ What Broke (And Took Time to Fix)

1. Dependency Hell

Upgrading Rails means upgrading everything.

Problems we faced:

  • Gems not compatible with Rails 7
  • Conflicting dependencies
  • Deprecated methods

👉 Solution:

  • Upgrade gems incrementally
  • Replace unmaintained libraries
  • Lock versions carefully

2. Zeitwerk Autoloading Issues

Rails 7 uses Zeitwerk by default, which is stricter.

Issues:

  • Naming mismatches
  • Improper file structures
  • Autoloading failures

👉 Fix:

  • Follow Rails naming conventions strictly
  • Ensure file paths match class names

3. Background Jobs & Async Behavior

Sidekiq / Resque jobs behaved differently after upgrade.

Issues:

  • Serialization changes
  • Job failures due to dependency changes

👉 Fix:

  • Test all background jobs separately
  • Monitor queues during rollout

4. Frontend & Asset Pipeline Changes

If you're using older asset pipeline setups:

  • Webpacker → replaced
  • JS handling changed
  • CSS pipelines affected

👉 Fix:

  • Move to modern setup (esbuild / importmaps)
  • Clean unused assets

✅ What Worked Well

1. CI-Based Upgrade Strategy

We didn’t upgrade everything at once.

Instead:

  • Small incremental changes
  • CI checks at every step
  • Parallel test runs

👉 This reduced risk significantly.


2. Staged Rollouts

We didn’t deploy everything in one go.

  • Tested in staging
  • Gradual production rollout
  • Monitored errors closely

👉 Avoid “big-bang deployment”


3. Strong Test Coverage Saved Us

Without tests, this would have been impossible.

Tests helped us:

  • Detect breaking changes early
  • Validate behavior after upgrade

🧠 What I’d Do Differently

If I do this again:

  • Upgrade Rails more frequently (don’t wait years)
  • Remove unused gems early
  • Add stricter linting before migration
  • Automate dependency checks

👉 Upgrades should be continuous, not painful events.


🚀 Practical Migration Strategy

If you’re planning a Rails upgrade:

  1. Upgrade Ruby version first
  2. Fix deprecations before upgrading Rails
  3. Upgrade Rails step-by-step (5 → 6 → 7)
  4. Run full test suite at every step
  5. Monitor logs during deployment

📌 Final Takeaway

Rails upgrades are not just technical tasks.

They reveal:

  • Code quality
  • System design decisions
  • Hidden technical debt

If done right, an upgrade can:

  • Improve performance
  • Increase developer productivity
  • Make your system future-ready

⭐️ Treat upgrades as part of engineering—not as a crisis to solve later.