Upgrading from Rails 7.2 to Rails 8 - The Latest and Greatest

Rails 8 (released November 2024) is the smoothest upgrade yet. The focus? Simplicity and performance - removing external dependencies while boosting speed.

Solid Queue, Solid Cache, and Solid Cable eliminate Redis for many use cases. Built-in authentication removes the need for Devise. Ruby 3.4 (latest stable) with continued YJIT improvements delivers excellent performance.

Note: This is Part 5 of our Rails Upgrade Series. Read Part 1: Planning Rails Upgrade for the overall strategy.

Before We Start

Expected Timeline: 1-2 weeks for medium-sized applications (easiest upgrade!)

Medium-sized application: 20,000-50,000 lines of code, 30-100 models, moderate test coverage, 2-5 developers. Smaller apps may take 1-2 weeks, larger enterprise apps 6-12 weeks.

Prerequisites:

  • Currently on Rails 7.2 (upgrade from 7.1 first if needed)
  • Ruby 3.1.0+ installed (Ruby 3.4 strongly recommended)
  • Test coverage of 80%+
  • Understanding of background job setup

Rails 8 requires Ruby 3.1.0 minimum, but Ruby 3.4 (latest stable) is strongly recommended for maximum performance.

Why Ruby 3.4?

Ruby 3.4 (December 2024) - Latest stable:

  • it as default block parameter - Cleaner block syntax
  • Prism parser improvements - Faster parsing
  • YJIT optimizations - Continued performance improvements
  • Better memory efficiency - Reduced memory usage
  • Enhanced pattern matching - More powerful syntax
  • Improved error messages - Better debugging experience

Ruby 3.3 (December 2023) - Also excellent:

  • Prism parser - New default parser
  • RJIT - Pure Ruby JIT compiler
  • M:N thread scheduler - Better concurrency
  • 15-20% faster than Ruby 3.2 with YJIT

Ruby 3.2 (December 2022) - Stable choice:

  • Production-ready YJIT - Stable and fast
  • WASI support - WebAssembly integration
  • Data class - Immutable value objects

Upgrade Ruby

# Check current Ruby version

ruby -v

# Install Ruby 3.4 (recommended - latest stable)

rbenv install 3.4.1
rbenv local 3.4.1

# Or Ruby 3.3 (also good)

rbenv install 3.3.6
rbenv local 3.3.6

# Verify

ruby -v
# => ruby 3.4.1


# Update bundler

gem install bundler
bundle install

Enable YJIT (Critical for Performance)

# config/boot.rb

ENV['RUBY_YJIT_ENABLE'] = '1'

# Or set in environment

export RUBY_YJIT_ENABLE=1

Performance gain: Ruby 3.4 continues YJIT improvements, 15-20% faster than Ruby 3.2, or 30-40% faster than Ruby 2.7.

Test with Ruby 3.4

# Run full test suite

bundle exec rails test

# Check YJIT stats

rails runner 'puts RubyVM::YJIT.runtime_stats' | grep ratio

Step 2: Update the Gemfile

# Gemfile


# Update Rails

gem 'rails', '~> 8.0.0'

# Solid Queue (replaces Sidekiq/Resque for many use cases)

gem 'solid_queue'

# Solid Cache (database-backed caching)

gem 'solid_cache'

# Solid Cable (WebSocket without Redis)

gem 'solid_cable'

# Keep existing gems

gem 'importmap-rails'
gem 'turbo-rails'
gem 'stimulus-rails'
gem 'sprockets-rails'
gem 'puma', '>= 5.0'
gem 'bootsnap', require: false

# Database adapters

gem 'pg', '~> 1.1' # PostgreSQL

# or

gem 'mysql2', '~> 0.5' # MySQL


# Optional: Remove if migrating to Solid alternatives

# gem 'sidekiq' # Can be replaced by Solid Queue

# gem 'redis' # Can be replaced by Solid Cache/Cable
bundle update rails
bundle install

Step 3: Run the Update Task

rails app:update

Review changes to:

  • config/application.rb
  • config/environments/*.rb
  • config/initializers/new_framework_defaults_8_0.rb

Solid Queue is a database-backed job queue that eliminates Redis dependency for background jobs.

When to Use Solid Queue

Good fit:

  • Low to medium job volume (< 1000 jobs/minute)
  • Simple job processing needs
  • Want to eliminate Redis
  • PostgreSQL or MySQL database

Stick with Sidekiq/Resque if:

  • High job volume (> 1000 jobs/minute)
  • Complex job scheduling needs
  • Already have Redis infrastructure
  • Need advanced features (unique jobs, batches)

Install Solid Queue

# Install Solid Queue

rails solid_queue:install

# This creates:

# - db/queue_schema.rb

# - config/queue.yml

# - bin/jobs (worker script)
# Run migrations

rails db:migrate

Configure Solid Queue

# config/queue.yml

production:

  dispatchers:

    - polling_interval: 1

      batch_size: 500

  workers:

    - queues: "*"

      threads: 3

      processes: 2

      polling_interval: 0.1
# config/environments/production.rb

config.active_job.queue_adapter = :solid_queue

Migrate from Sidekiq

# Before (Sidekiq)

class MyJob < ApplicationJob
  queue_as :default

  def perform(user_id)
    # Job logic

  end
end

# After (Solid Queue) - Same code!

class MyJob < ApplicationJob
  queue_as :default

  def perform(user_id)
    # Job logic - no changes needed

  end
end

Run Solid Queue

# Development

bin/jobs

# Production (with systemd, Docker, or Kamal)

bundle exec rake solid_queue:start

Step 5: Solid Cache (Optional)

Solid Cache is a database-backed cache store that eliminates Redis for caching.

Install Solid Cache

rails solid_cache:install
rails db:migrate

Configure Solid Cache

# config/environments/production.rb

config.cache_store = :solid_cache_store

Usage (Same as Before)

# Fragment caching - no changes

<% cache @post do %>
  <%= render @post %>
<% end %>

# Low-level caching - no changes

Rails.cache.fetch("user_#{user.id}") do
  user.expensive_calculation
end

Performance Considerations

Pros:

  • No Redis dependency
  • Automatic cleanup of old entries
  • Works with existing database

Cons:

  • Slower than Redis for high-traffic sites
  • Database load increases

Recommendation: Use Solid Cache for low to medium traffic. Keep Redis for high-traffic applications.

Step 6: Solid Cable (Optional)

Solid Cable provides WebSocket support without Redis.

Install Solid Cable

rails solid_cable:install
rails db:migrate

Configure Solid Cable

# config/cable.yml

production:
  adapter: solid_cable

# Or keep Redis if we have it

# production:

#   adapter: redis

#   url: redis://localhost:6379/1

Usage (No Changes)

# app/channels/chat_channel.rb

class ChatChannel < ApplicationCable::Channel
  def subscribed
    stream_from "chat_#{params[:room_id]}"
  end

  def receive(data)
    ActionCable.server.broadcast(
      "chat_#{params[:room_id]}",
      data
    )
  end
end

Step 7: Built-in Authentication Generator

Rails 8 includes a built-in authentication generator - no Devise needed for simple use cases.

Generate Authentication

rails generate authentication

This creates:

  • User model with password authentication
  • SessionsController for login/logout
  • PasswordsController for password reset
  • Authentication views
  • Helper methods

What We Get

# app/models/user.rb

class User < ApplicationRecord
  has_secure_password

  generates_token_for :password_reset, expires_in: 15.minutes
  generates_token_for :email_confirmation, expires_in: 24.hours
end
# app/controllers/application_controller.rb

class ApplicationController < ActionController::Base
  before_action :authenticate

  private

  def authenticate
    if session_record = Session.find_by(id: cookies.signed[:session_id])
      Current.session = session_record
    else
      redirect_to new_session_path
    end
  end
end

When to Use Built-in Auth vs Devise

Use built-in authentication:

  • Simple authentication needs
  • Want full control over auth code
  • Learning Rails authentication
  • Small to medium applications

Use Devise:

  • Need OAuth integration
  • Complex authentication requirements
  • Multi-tenancy
  • Advanced features (confirmable, lockable, etc.)

Migrate from Devise (If Needed)

# Keep the existing User model

# Add has_secure_password

class User < ApplicationRecord
  has_secure_password

  # Keep existing Devise functionality we need

  # Remove Devise modules we don't use

end

# Gradually migrate authentication logic

# Test thoroughly before removing Devise

Step 8: Progressive Web App (PWA) Support

Rails 8 adds built-in PWA support.

Generate PWA Files

rails generate pwa

This creates:

  • app/views/pwa/manifest.json.erb - PWA manifest
  • app/views/pwa/service-worker.js - Service worker
  • Icons and configuration

Configure PWA

<!-- app/views/layouts/application.html.erb -->
<head>
  <%= tag.link rel: "manifest", href: pwa_manifest_path %>
  <%= tag.meta name: "apple-mobile-web-app-capable", content: "yes" %>
</head>
# config/routes.rb

get "manifest" => "pwa#manifest", as: :pwa_manifest
get "service-worker" => "pwa#service_worker", as: :pwa_service_worker

Step 9: Breaking Changes (Minimal!)

Rails 8 has very few breaking changes - this is the smoothest upgrade.

1. Deprecations from Rails 7 Removed

# If we fixed Rails 7 deprecation warnings, we're good!

# Check for any remaining warnings:

RAILS_ENV=test rails test 2>&1 | grep -i deprecat

2. Default Configuration Changes

# config/initializers/new_framework_defaults_8_0.rb

# Review and enable new defaults


Rails.application.config.load_defaults 8.0

3. ActiveStorage Changes

# ActiveStorage::Blob#open without block now returns file

# Before (Rails 7)

blob.open do |file|
  # Use file

end

# After (Rails 8) - both work

blob.open do |file|
  # Use file

end

# Or without block

file = blob.open
# Use file

file.close

Step 10: Testing Updates

Test Solid Queue Jobs

# test/jobs/my_job_test.rb

require "test_helper"

class MyJobTest < ActiveJob::TestCase
  test "performs job" do
    assert_enqueued_with(job: MyJob, args: [1]) do
      MyJob.perform_later(1)
    end
  end

  test "processes job" do
    MyJob.perform_now(1)
    # Assert job effects

  end
end

Test Authentication

# test/controllers/posts_controller_test.rb

class PostsControllerTest < ActionDispatch::IntegrationTest
  setup do
    @user = users(:one)
    sign_in @user
  end

  test "should get index" do
    get posts_url
    assert_response :success
  end
end

Step 11: Performance Improvements

Rails 8 + Ruby 3.4 delivers significant performance gains:

  • 15-20% faster than Ruby 3.2 (or 30-40% faster than Ruby 2.7)
  • Lower memory usage (Ruby 3.4 improvements)
  • Faster boot times (Prism parser improvements)
  • Reduced infrastructure costs (no Redis needed)

Benchmark YJIT Performance

# config/initializers/yjit_stats.rb

if defined?(RubyVM::YJIT) && RubyVM::YJIT.enabled?
  Rails.application.config.after_initialize do
    at_exit do
      stats = RubyVM::YJIT.runtime_stats
      puts "\n=== YJIT Stats ==="
      puts "Compiled: #{stats[:compiled_iseq_count]} methods"
      puts "Ratio: #{stats[:ratio]}%"
      puts "==================\n"
    end
  end
end

Monitor Solid Queue Performance

# Check job queue depth

SolidQueue::Job.pending.count

# Check failed jobs

SolidQueue::Job.failed.count

# Monitor in production

# Use the APM tool (New Relic, Datadog, etc.)

Step 12: Deployment with Kamal 2

Rails 8 includes Kamal 2 for zero-downtime deployments.

Install Kamal

# Kamal is included by default

# Initialize configuration

kamal init

Configure Kamal

# config/deploy.yml

service: myapp

image: myapp/production


servers:

  web:

    hosts:

      - 192.168.1.1

    labels:

      traefik.http.routers.myapp.rule: Host(`myapp.com`)

    options:

      network: "private"



registry:

  server: ghcr.io

  username: myusername

  password:

    - KAMAL_REGISTRY_PASSWORD


env:

  secret:

    - RAILS_MASTER_KEY

Deploy

# First deployment

kamal setup

# Subsequent deployments

kamal deploy

# Rollback if needed

kamal rollback

Upgrade Checklist

Note: This checklist covers the most common changes. Depending on the application’s gems, custom code, and architecture, we may encounter additional issues. Always test thoroughly in a staging environment.

  • Upgrade Ruby to 3.1+ (3.4 recommended)
  • Enable YJIT for performance
  • Update Gemfile with Rails 8.0
  • Run rails app:update
  • Decide on Solid Queue (optional)
  • Decide on Solid Cache (optional)
  • Decide on Solid Cable (optional)
  • Consider built-in authentication (optional)
  • Enable PWA support (optional)
  • Fix any deprecation warnings
  • Run full test suite
  • Test in staging environment
  • Deploy to production with monitoring

Common Gotchas

1. Solid Queue vs Sidekiq

# Solid Queue doesn't support all Sidekiq features

# Check compatibility before migrating:

# - Unique jobs -> Use database constraints

# - Batches -> Implement manually

# - Scheduled jobs -> Supported

# - Retries -> Supported

2. Database Load with Solid Cache

# Monitor database performance

# Solid Cache adds queries to our database

# Consider keeping Redis for high-traffic sites


# Check cache hit rate

Rails.cache.stats

3. Authentication Migration

# Don't rush to remove Devise

# Test built-in auth thoroughly first

# Migrate gradually if needed

Migration Strategy

Conservative Approach

  1. Upgrade to Rails 8 first
  2. Keep existing infrastructure (Redis, Sidekiq, Devise)
  3. Test thoroughly
  4. Gradually adopt Solid gems if beneficial

Progressive Approach

  1. Upgrade Ruby to 3.4
  2. Upgrade to Rails 8
  3. Migrate to Solid Queue for new jobs
  4. Evaluate Solid Cache for non-critical caching
  5. Keep Redis for high-traffic features

Aggressive Approach

  1. Upgrade Ruby to 3.4
  2. Upgrade to Rails 8
  3. Migrate all jobs to Solid Queue
  4. Replace Redis with Solid Cache/Cable
  5. Use built-in authentication for new features

Recommendation: Start conservative, move progressive as we gain confidence.

What’s Next

Congratulations!

We’ve completed the Rails upgrade journey from planning through Rails 8.

Series recap:

  • Part 1: Strategic planning and preparation
  • Part 2: Rails 4.2 to 5 - Foundation updates
  • Part 3: Rails 5.2 to 6 - Zeitwerk and Webpacker
  • Part 4: Rails 6.1 to 7 - Import Maps and Hotwire
  • Part 5: Rails 7.2 to 8 - Solid gems and simplification

Keep the Rails App Modern

  • Monitor deprecation warnings in each Rails version
  • Upgrade Ruby regularly for performance and security
  • Test thoroughly at each step
  • Stay informed about Rails releases
  • Contribute back to the Rails community

Resources


At Saeloun, we’ve helped numerous teams successfully upgrade to Rails 8 and modernize their infrastructure.

Whether planning a major upgrade or needing help optimizing a Rails 8 application, we’re here to help.

Contact us for Rails upgrade consulting


Need help on your Ruby on Rails or React project?

Join Our Newsletter