If you are on Rails 7.2 and staring at Rails 8, you are in the happiest version of this migration. 7.2 was specifically shaped as the on-ramp to 8. Most of the hard work - Zeitwerk defaults, Trilogy, async query support, the new framework defaults - already happened when you got to 7.2.
So Rails 7.2 to 8 is usually a short, boring upgrade. If you sequence it right and do not try to also adopt every Rails 8 feature in the same PR.
This is the focused step-by-step. If you are on Rails 7.0 or 7.1, start with the broader Rails 7 to Rails 8 upgrade guide and come back to this when you are on 7.2.
Pre-Flight Checklist
Do not start until all of these are true:
- You are on the latest Rails 7.2.x patch release.
- Your Ruby version is 3.2 or later (3.3.x recommended).
bundle exec rspecpasses, fully, with zero flakes.bundle outdated --only-explicithas been reviewed in the last month.bundle exec bundle-audit check --updateis clean.- You have a staging environment that actually mirrors production.
- Deploys are a single command, by any engineer, with a rollback path.
If any of those is false, fix it first. Upgrading Rails on a shaky base is the number-one reason “simple upgrades” become emergencies.
Step 1: Create a Dedicated Upgrade Branch
git checkout -b upgrade/rails-8
Keep this branch narrow. Only the bump and its immediate fallout. New features, refactors, and opportunistic cleanups belong in other PRs.
Step 2: Bump Ruby (If Needed)
Rails 8 requires Ruby 3.2+. Most 7.2 teams are on 3.2 or 3.3 already, but verify:
ruby -v
cat .ruby-version
If you are on 3.1 or earlier, bump Ruby first as a separate PR and deploy. Do not combine Ruby and Rails bumps in one project.
# .ruby-version
3.3.6
# Dockerfile (if applicable)
FROM ruby:3.3.6-slim
Ship Ruby first. Let it bake. Then come back here.
Step 3: Bump Rails
# Gemfile
gem "rails", "~> 8.0.0"
bundle update rails
Expect bundle update rails to surface a handful of gems that pin to < 8.0. Common culprits (check each against current gem versions - this list ages):
- Older versions of
devise - Older versions of
pundit,cancancan - Rails-adjacent gems pinned to 7.x (any
*-railsgem) - Sprockets if you are still on it
For each, check the gem’s changelog. Usually a newer version supports Rails 8. Bump it. If a gem has genuinely not updated, evaluate whether it is still maintained - that is a separate signal worth acting on.
Step 4: Run rails app:update
bundle exec rails app:update
This is interactive. Read every diff. For a Rails 7.2 starting point, the changes are fairly small compared to jumping from 7.0. Expect prompts for:
config/application.rb-load_defaults 8.0.config/environments/development.rb,production.rb,test.rb.config/initializers/new_framework_defaults_8_0.rb- a new initializer listing each individual default. Keep this file. Flip defaults one by one once the bump is stable.bin/*scripts - minor changes, usually safe.Dockerfile(if you have one generated by Rails) - may get updated.
Do not accept everything blindly. In particular, load_defaults 8.0 flips a number of subtle behaviors. The standard pattern is:
# config/application.rb
config.load_defaults 7.2
And keep a populated config/initializers/new_framework_defaults_8_0.rb. Flip each default intentionally, one PR at a time, after the bump ships. Then eventually bump to config.load_defaults 8.0 and delete the initializer.
Step 5: Review Critical Config
config/database.yml
Rails 8 adopts new defaults for connection pooling and prepared statements. If your database.yml is explicit, you may need to add or adjust:
production:
<<: *default
database: myapp_production
# prepared_statements defaults changed in Rails 8 - verify
config/cache.yml (new)
Only matters if you adopt Solid Cache. For the upgrade itself, leave your existing cache store alone.
config/queue.yml (new)
Same - only matters if you adopt Solid Queue. Keep Sidekiq / GoodJob exactly as-is for the upgrade.
config/puma.rb
Rails 8’s default Puma config is slightly different. If you customized yours, diff the new generator output against your existing file and merge deliberately.
Step 6: Run the Tests
bundle exec rspec
Expect some breakage. The common categories from 7.2 to 8:
Deprecation warnings turned errors
Rails 7.2 deprecations are Rails 8 removals. If your app had warnings like “X will be removed in Rails 8” and you ignored them, now is when they fail. Search the commits for DEPRECATION WARNING in staging logs over the past year.
ActiveRecord::Base.connection usage
Rails 8 prefers ActiveRecord::Base.lease_connection (or role-aware handlers) for some cases. Audit lib/ and app/ for bare .connection calls that bypass the connection pool.
find_or_create_by semantics
Rails 8 tightens behavior around unique constraint conflicts. If you have high-concurrency find_or_create_by calls, review them for new edge cases.
Zeitwerk strictness
Already the default in 7.2, but Rails 8 enforces more aggressively at boot. Run:
bundle exec rails runner "Rails.application.eager_load!"
Fix any autoload errors before deploying.
System specs / browser specs
Re-run browser-based tests with the latest Capybara and Selenium. Rails 8 doesn’t change browser behavior, but upgrade-adjacent gem bumps often do.
Step 7: Boot It Locally, Click Around
Automated tests miss things. Especially:
- Login / session persistence
- File uploads (ActiveStorage)
- Mailer previews
- Action Cable / Turbo Streams
- Background job enqueuing
Walk through these manually before merging. This is 20 minutes that saves 2 hours of staging debugging.
Step 8: Deploy to Staging
Ship the branch to a real staging environment. Keep it there at least a few days. Watch:
- Boot times
- Memory usage (Rails 8 can have slightly different memory profiles)
- Error monitor (any new exception signatures?)
- Response times
If something is odd, it is far cheaper to find it in staging than after production rollout.
Step 9: Production Rollout
Options, roughly safest to riskiest:
- Canary / one-instance rollout: deploy to one app instance, watch metrics, then roll to the rest.
- Off-peak deploy: Tuesday or Wednesday, middle of the business day so humans are awake.
- Full deploy with fast rollback: just ensure your deploy tool can redeploy the previous image in under 5 minutes.
Have a rollback image identified before you deploy. A Rails major upgrade rollback is a container / Gemfile.lock rollback, not a git revert. Your platform needs to support that cleanly.
Step 10: Let It Bake, Then Adopt Rails 8 Features
After the upgrade is stable in production - usually 1-2 weeks - then decide feature by feature:
Solid Cache
Worth it if you are currently paying for Redis primarily for cache. Migrate gradually - keep Redis for Action Cable or Sidekiq if you use them, and move only the Rails.cache store to Solid Cache first.
# config/environments/production.rb
config.cache_store = :solid_cache_store
Deploy this as its own PR, with a rollback plan to your previous cache store.
Solid Queue
Only consider if you want to drop Redis-based job backends. Benchmark on your real workload before committing - Sidekiq is hard to beat on throughput for some patterns.
Built-in authentication
Almost never worth swapping a working Devise setup for the built-in generator. New apps, yes. Existing apps, no.
Propshaft
If you are still on Sprockets and it works, leave it. Migrating to Propshaft is a separate project with its own surprises (custom helpers, asset path assumptions, CDN caching).
Flipping load_defaults 8.0
Once all individual defaults in new_framework_defaults_8_0.rb have been flipped and tested, remove the initializer and set config.load_defaults 8.0 in config/application.rb. This is the final step of the upgrade, sometimes weeks after the Gemfile bump.
Specific Rails 7.2 → 8 Gotchas
Beyond the general 7-to-8 gotchas, a few things specifically surprise 7.2 teams:
You might already be on Trilogy
Rails 7.2 made Trilogy a first-class MySQL adapter. If you opted in on 7.2, Rails 8 is mostly invisible here. If you are still on mysql2, Rails 8 is a good time to evaluate - but not mandatory.
Async queries
7.2 introduced more async query paths. Rails 8 expands on them. Nothing breaks, but if you adopted load_async in 7.2, retest behavior under load on 8.
config.active_record.raise_on_assign_to_attr_readonly
Became stricter. If you relied on silent ignoring of writes to readonly attributes, you’ll get raises now.
Rubocop / standard
Not a Rails issue, but 7.2 apps on older Rubocop versions sometimes fail the upgrade CI run. Bump your linter versions before debugging mysterious failures.
Estimated Timeline
A well-maintained Rails 7.2 app that followed the pre-flight checklist:
- Upgrade PR: 2-5 days of focused engineering work.
- Staging bake: 3-7 days of wall time.
- Production deploy: a single afternoon.
- Full Rails 8 feature adoption: several more weeks, stretched out.
If you are hitting weeks of pain on the upgrade PR itself, stop. Something in the pre-flight checklist was not actually done. Fix that, then resume.
Related Reading
- Rails 7 to Rails 8 upgrade: 2026 technical guide - if you are on 7.0 or 7.1, start there.
- Rails 7 LTS: A developer’s technical guide - if you are not upgrading yet.
- When to upgrade Rails
- Stop wasting money on one-off Rails upgrades
Want expert eyes on your Rails 7.2 to 8 upgrade? Rails Upgrade Express runs these migrations end to end, a Rails technical audit gives you a realistic scope before you commit, and a Rails Care Plan keeps you at the latest version so the next upgrade is an afternoon, not a project.
Schedule a consultation or email hello@railsfever.com to talk through your Rails 7.2 to 8 upgrade.