Rails 8 Upgrade Checklist

Upgrading a Rails application to a new major version is one of those tasks that looks simple from the outside — bump a number in the Gemfile, run bundle update, fix what breaks — and consistently takes three to ten times longer than anyone estimates. The gap between expectation and reality is where this guide lives. It connects to the broader Debugging and Maintenance topic and covers the full surface of a Rails 8 upgrade: deprecation triage, gem compatibility audits, building a test matrix, navigating configuration changes, planning your rollback, and dealing with the subtle behavioural shifts that no changelog will warn you about. I have been through enough major Rails upgrades — from 3.2 to 4.0, from 4.2 to 5.0, and every step since — to know that the technical steps are the easy part. The hard part is the things that silently change underneath you.
Before you touch the Gemfile
Upgrades fail when they start too early. Before you change a single line of code, do three things:
1. Read the release notes and the upgrade guide. The official Rails upgrade guide covers framework-level changes, deprecations, and required configuration updates. Read the entire section for your version jump, not just the bullet points. The details matter.
2. Run your existing test suite and record the results. You need a clean baseline. If your tests are already failing, fix them first. Upgrading Rails on top of a broken test suite is a recipe for confusion — you will not know which failures are upgrade-related and which were pre-existing.
3. Check your Ruby version. Rails 8 requires Ruby 3.2 or later. If you are on an older Ruby, that is a separate upgrade that should happen first and be deployed independently. Do not upgrade Ruby and Rails in the same pull request. Each major dependency change deserves its own deployment cycle so you can isolate failures.
Deprecation triage
Every Rails major release removes features that were deprecated in the previous minor release. Rails 8 is no exception. The deprecation warnings you have been ignoring in your test output are now errors.
Run your full test suite with RAILS_ENV=test and search the output for "DEPRECATION WARNING." Collect them all. Group them by category:
- Framework deprecations. Methods, configuration options, or behaviours that Rails itself has removed. These require code changes in your application.
- Gem-triggered deprecations. Warnings that come from gems calling deprecated Rails APIs. These require gem updates, not application code changes.
- Your own code. Direct calls to deprecated methods in controllers, models, or views.
Prioritise gem-triggered deprecations first, because you need to know whether updated versions of those gems even exist before committing to the upgrade. If a critical gem has not been updated for Rails 8 compatibility and has no fork or alternative, that is a blocking issue you want to discover now, not three days into the upgrade.
For each framework deprecation, the warning message usually includes the replacement. Follow it. Do not write clever wrappers to preserve the old behaviour — that just delays the pain and creates confusing code for the next developer.
Gem compatibility audit
This is where most upgrade timelines shatter. Open your Gemfile.lock and audit every gem against Rails 8 compatibility.
The practical approach:
- Start with your critical path gems. Authentication (Devise, Rodauth), background jobs (Sidekiq, GoodJob), admin panels (ActiveAdmin, Administrate, Avo), search (Ransack, Searchkick), API serialisation (Alba, Blueprinter, jbuilder). If any of these do not support Rails 8, your upgrade is blocked.
- Check each gem's changelog, release notes, or GitHub issues. Search for "Rails 8" in the issue tracker. Look at the CI matrix in the gem's repository — does it test against Rails 8?
- Identify gems that are abandoned. No commits in over a year, open issues with no responses, no Rails 8 CI badge. These need replacements, not updates.
- Check for gems that vendor or monkey-patch Rails internals. These are the highest-risk dependencies in any major upgrade. A gem that overrides
ActiveRecord::Base.connectionor patchesActionController::Parameterswill break in ways that produce baffling error messages far from the actual cause.
Create a spreadsheet or markdown table: gem name, current version, Rails 8-compatible version, status (compatible / needs update / needs replacement / blocking). This table is your upgrade project plan. Everything else flows from it.
Build a test matrix
Do not upgrade Rails in a single leap. Build a matrix:
| Step | Ruby | Rails | Purpose |
|---|---|---|---|
| 1 | Current | Current | Baseline — all tests green |
| 2 | 3.2+ | Current | Isolate Ruby upgrade issues |
| 3 | 3.2+ | 7.2.x (latest) | Pick up final deprecation removals |
| 4 | 3.2+ | 8.0.x | The actual upgrade |
Each step should be a separate branch, a separate PR, and a separate deployment. Yes, this is slower than a single jump. It is also dramatically easier to debug when something breaks, because you know exactly which change caused the failure.
Run your CI suite at each step. Fix failures before moving to the next step. This is not optional — compounding failures across multiple version jumps turns a three-day project into a three-week project.
Configuration changes
Rails major versions change default configuration values. Rails 8 is no different. The key mechanism is config.load_defaults.
In config/application.rb, you will have something like:
config.load_defaults 7.1
Do not change this to 8.0 immediately. Instead:
- Keep
config.load_defaultsat your current version. - Open
config/initializers/new_framework_defaults_8_0.rb(generated byrails app:update). - Read each setting. Understand what it changes. Enable them one at a time.
- Test after each change.
Some defaults are benign — a new default cache format, a different Active Storage analyser. Others can change application behaviour — cookie serialisation format, session store configuration, Active Record encryption defaults. Enabling them all at once and then debugging a broken production deploy is not a path you want to walk.
Pay particular attention to:
- Cookie and session serialisation. If the default serialiser changes, existing user sessions may become unreadable after deploy, logging out every active user. Test this with production-like session data.
- Active Record query behaviour. Changes to
whereclause handling, enum definitions, or association loading can change which records your queries return. This is the kind of bug that passes all tests and breaks in production because test data does not exercise the edge case. - Active Job serialisation. If you have jobs enqueued before the upgrade that deserialise after it, format changes can cause silent failures.
Rollback planning
Every upgrade needs a rollback plan. Not "we'll figure it out." An actual, written plan.
For a Rails major upgrade, the rollback concerns are:
- Database migrations. If your upgrade includes migrations, can they be reversed? Are there destructive migrations (removing columns, changing types) that make rollback impossible? If so, split them: deploy the migration separately before the Rails upgrade, with a compatibility period where the old code still works.
- Session and cookie compatibility. If serialisation formats change, users who got new-format cookies during the upgrade window will have broken sessions after rollback. Understand this before deploying.
- Background job queues. Jobs enqueued with the new Rails version may fail to deserialise under the old version. Drain queues before rolling back, or accept that some jobs will need manual replay.
- Caching. If cache key formats or serialisation changes, your cache is effectively invalid after upgrade and again after rollback. Plan for cold caches in both directions.
The simplest rollback strategy: keep the old branch deployable for at least a week after the upgrade. Do not merge follow-up work on top of the upgrade PR until you are confident production is stable.
What usually goes wrong
These are the upgrade failures I see repeatedly, across teams of every size:
- One giant PR. Someone bumps Rails, updates 30 gems, fixes 200 deprecations, changes configuration defaults, and opens a 4,000-line pull request. Nobody can review it meaningfully. A bug ships. Nobody knows which change caused it. Do incremental upgrades.
- Skipping the gem audit. The upgrade starts, hits a gem incompatibility three days in, and now the branch is half-migrated and cannot go forward or backward. Audit first.
- Ignoring deprecation warnings. They were warnings. Now they are errors. The volume of required fixes is proportional to how long you ignored the warnings.
- Changing
load_defaultsin one step. This enables dozens of new behaviours simultaneously. When something breaks, the search space is enormous. Enable them individually. - No rollback plan. "We'll just roll forward" is not a plan — it is optimism. Optimism does not fix a broken production deploy at 6 PM on a Friday.
- Testing only with seeds, not production-like data. Your seed data is clean. Production data has nulls where you do not expect them, UTF-8 edge cases, records created under three different Rails versions, and associations that violate constraints added years after the data was created. Test with a production database dump (sanitised, obviously).
Upgrade checklist
Print this. Check each box. Do not skip steps.
- Read the official upgrade guide for your version jump
- Confirm Ruby version meets Rails 8 minimum (3.2+)
- Run full test suite — establish green baseline
- Audit all gems for Rails 8 compatibility
- Resolve or replace incompatible/abandoned gems
- Address all deprecation warnings in test output
- Upgrade Ruby version if needed (separate deploy)
- Upgrade to latest Rails 7.x patch (separate deploy)
- Upgrade to Rails 8.0.x
- Run
rails app:updateand review generated changes - Enable new framework defaults one at a time
- Test session/cookie serialisation with production-like data
- Verify background job serialisation compatibility
- Write and test rollback plan
- Deploy to staging with production database copy
- Soak test on staging for at least 48 hours
- Deploy to production during low-traffic window
- Monitor error rates, response times and job failures for 72 hours
- Keep old branch deployable for one week post-upgrade
FAQ
How long does a Rails 8 upgrade take?
For a small application with good test coverage and up-to-date gems: a few days. For a large application with legacy gems, weak tests and years of accumulated deprecation warnings: two to six weeks. The gem audit determines the timeline more than anything else.
Can I skip Rails 7.2 and go straight from 7.0 to 8.0?
Technically, yes. Practically, I would not recommend it. Each minor version introduces deprecation warnings for the next version's removals. Skipping 7.1 and 7.2 means you encounter all those removals at once, with no warning messages to guide you. The incremental path is slower but produces better outcomes.
What if a gem I depend on does not support Rails 8?
You have three options: wait for the gem to be updated, fork the gem and fix the incompatibility yourself, or replace the gem with an alternative. If it is a critical gem with an active maintainer, waiting is usually the right call. If the gem is abandoned, replacement is the only sustainable option.
Should I upgrade Rails and Ruby at the same time?
No. Upgrade Ruby first, deploy it, confirm stability, then upgrade Rails. Combining them doubles the failure surface and makes it significantly harder to identify the cause of any breakage.
Do I need to rewrite tests during the upgrade?
Usually not rewrite — but you may need to update them. Changes to controller test helpers, fixture loading, or integration test behaviour across Rails versions can cause test failures that are not bugs in your application. Fixing these is part of the upgrade, not a separate task.
Related reading
- Debugging and Maintenance — parent topic covering production debugging and codebase health
- Make an Old Rails App Safer to Change — learning path for stabilising an application before attempting an upgrade
- Debugging Production Rails Issues — triage workflows for when the upgrade causes production problems