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

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:
- Upgrade Ruby version first
- Fix deprecations before upgrading Rails
- Upgrade Rails step-by-step (5 → 6 → 7)
- Run full test suite at every step
- 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.