Rails 7 to 8 Upgrade Checklist

The upgrade is on the calendar and the branch is not open yet. This page is the run-sheet: every step as a checkbox, each with one line that tells you when it is done. The reasoning behind the items lives in our working guide to upgrading Rails 7 to 8; follow the links when an item needs more than a line. If you are further back than 7.2, start with our Rails 6 to 7 guide and come back.

Pre-flight

Do not open the upgrade branch until every box in this section is checked.

  • You are on the latest Rails 7.2 patch release. Done when: bin/rails -v prints the newest 7.2.x. The official process moves one minor version at a time, from the latest patch, fixing tests and deprecation warnings at each hop. If you are on 7.0 or 7.1, do those hops first.
  • Leftovers from the 7.1 to 7.2 hop are closed out. Done when: your tests respect config.active_job.queue_adapter, and nothing depends on alias_attribute reaching custom attribute methods. Skip this if 7.2 has been running quietly for months.
  • Ruby is at 3.2.0 or newer, shipped as its own deploy. Done when: production already runs Ruby 3.2 or newer. Rails 8.0 and 8.1 both require it. Rails 7.2 runs on Ruby 3.1, so you can raise Ruby first while Rails stays put; the official guide recommends upgrading Ruby and Rails separately.
  • The suite passes with zero deprecation warnings. Done when: a full test run prints no deprecation output. Every warning you clear here is a breaking change you will not meet on the branch.
  • Coverage is real on the money paths. Done when: the flows the business depends on are covered by tests you trust. We hold client projects at 80-90% test coverage; the money paths matter more than the exact number.
  • Every gem has a released Rails-8-compatible version. Done when: you have checked each entry in the Gemfile and none blocks Rails 8. Git-pinned forks count; check those too.
  • Staging mirrors production. Done when: the upgrade can run somewhere production-shaped before production sees it.
  • Rollback is one command. Done when: you can name the exact command that returns production to the previous release.

The version bump

  • The upgrade branch contains the upgrade and nothing else. Done when: no feature work, no refactors, no drive-by fixes are riding along.
  • Dual boot is a deliberate choice. Done when: you decided to dual boot or to skip it, and can say why. The guide covers the trade-offs.
  • bundle update rails resolves cleanly. Done when: Bundler resolves without pins you cannot explain and Gemfile.lock shows Rails 8.0.
  • bin/rails app:update has been run and every diff reviewed. Done when: you walked the interactive conflict session line by line, and config/initializers/new_framework_defaults_8_0.rb exists with every line still commented out.
  • config.load_defaults still says 7.2. Done when: config/application.rb is unchanged on this point. The new defaults come later, one at a time.
  • The suite is green on Rails 8. Done when: a full run passes on the upgrade branch with no deprecation output.

Breaking-change sweep

A deprecation-free 7.2 suite turns most of this section into a confirmation pass.

  • Enum definitions use the positional form. Done when: every enum passes the attribute name as the first argument. The keyword-argument form was removed in 8.0.
  • Nothing assumes db:migrate replays every migration on a fresh database. Done when: CI and developer setup still work from an empty database. db:migrate now loads the schema first; db:migrate:reset restores the replay-from-scratch behavior.
  • Removed configuration is gone from the codebase. Done when: a grep for each of these returns nothing: read_encrypted_secrets, commit_transaction_on_non_local_return, warn_on_records_fetched_greater_than, allow_deprecated_singular_associations_name, use_big_decimal_serializer, allow_deprecated_parameters_hash_equality, ActiveSupport::ProxyObject.
  • No view calls form_with model: nil. Done when: a grep across views and helpers returns nothing. That call was removed in 8.0, along with passing content to void tags on the tag builder.
  • Long-running regexes survive a one-second timeout. Done when: nothing in the app needs a regex to run longer than a second, or you have tuned the default where it does. Rails 8 sets Regexp.timeout to 1 second as ReDoS hardening.
  • Active Storage on Azure has a plan. Done when: you do not use the Azure backend, or its replacement is picked. The backend is deprecated in 8.0.

Ship it

  • The bump deploys alone. Done when: the release contains the upgrade branch and nothing else. We deliver major Rails and Ruby upgrades with zero downtime. Single-change releases are a big part of what makes that possible.
  • Error rates and queue latency have a watcher and a window. Done when: someone owns the graphs for an agreed window and knows what normal looked like before the deploy.
  • The rollback has been rehearsed. Done when: you have executed the rollback once before you need it, and it worked.

New framework defaults, one at a time

  • Each new default gets its own uncomment, test, deploy loop. Done when: a default has run in production without surprises before you uncomment the next one. Rails supports enabling the 8.0 defaults gradually across several deployments.
  • config.load_defaults 8.0 is flipped. Done when: every line in new_framework_defaults_8_0.rb is uncommented, production is stable, and config/application.rb now says 8.0.
  • The defaults file is deleted. Done when: new_framework_defaults_8_0.rb is gone and the suite still passes.

Adoption decisions (after it settles)

Nothing here blocks the upgrade. These are separate choices to make once Rails 8 has been boring in production for a while, and the guide covers each trade-off. Done when, for each: the decision is recorded where the next developer will find it.

  • Solid Queue, Solid Cache, and Solid Cable, or keep Redis. Solid Queue is built on FOR UPDATE SKIP LOCKED (PostgreSQL 9.5+, MySQL 8.0+) and also works with SQLite. Solid Cable keeps messages in the database for a day by default.
  • Propshaft, or stay on Sprockets. Propshaft is the default asset pipeline in Rails 8.
  • The authentication generator, or the auth you already run.
  • Kamal 2 and Thruster, or the deploy pipeline you already trust.
  • params.expect where params.require lives today. Rails 8 introduces it as the safer way to handle params.

The 8.1 hop

8.0 to 8.1 is a minor hop. The same rules apply: latest patch, green suite, one version at a time. Two specifics to expect:

  • The schema.rb diff is anticipated. Done when: you have committed the one-time diff from Rails 8.1 sorting each table’s columns alphabetically and confirmed it changes ordering only. Apps on structure.sql keep their exact column order.
  • Ruby stays put. Done when: you have confirmed the floor did not move. Rails 8.1 requires Ruby 3.2.0 or newer, the same as 8.0.

Run the pre-flight list today, before the branch exists. If one or two boxes fail, close them and keep moving. If half the section fails, the pre-flight is the real project, and it comes before anything else on this page. This site is a Rails 8 application deployed to Render. If you want another set of hands on the upgrade or on the pre-flight itself, start at Ruby on Rails.