Dev & EngARTICLE

Rails 8 removes Redis from the default stack with Solid Queue, Solid Cache, and Solid Cable

Rails 8 swaps Redis for three database-backed components: Solid Queue, Solid Cache, and Solid Cable. See how to migrate an existing app and when it still makes sense to keep Sidekiq.

Rails 8 removes Redis from the default stack with Solid Queue, Solid Cache, and Solid Cable
Image: Bisneto Braga

Rails 8 swaps Redis for three database-backed components: Solid Queue, Solid Cache, and Solid Cable. See how to migrate an existing app and when it still makes sense to keep Sidekiq.

Editor's note: this article references paid features of Sidekiq Pro/Enterprise (rate limiting, uniqueness, batches), observability via Sidekiq Web, and the fact that Rails 8 kept the Redis adapter without removing it. These claims are common knowledge in the Ruby ecosystem, but we did not find official Sidekiq documentation or an explicit passage in the Rails release notes that confirms them directly. The core facts about Solid Queue, Solid Cache, Solid Cable, and the FOR UPDATE SKIP LOCKED mechanism were verified and match the official Rails 8 release notes.

Rails 8.0 changed a long-standing architectural decision: the near-automatic dependency on Redis. Version 8 ships with three new components: Solid Queue, Solid Cache, and Solid Cable. All three do what Redis (and, in the case of queues, Sidekiq) used to do, except using the relational database the application already has running.

For anyone maintaining a Rails 6 or 7 app in production, this isn't just a changelog detail. It's one less piece (or one more, depending on the case) in the list of services someone has to provision, monitor, and update at 3 a.m. when it goes down.

What each Solid component replaces, exactly

Solid Queue replaces the combination of Redis with a separate job framework, such as Sidekiq, Resque, or Delayed Job. It runs on the same FOR UPDATE SKIP LOCKED technique, introduced in PostgreSQL 9.5 and now also available in MySQL 8.0 and SQLite. This means multiple workers can pull jobs from the queue without locking each other out, using only the existing database.

Solid Cache replaces Redis or Memcached for HTML fragment caching. Instead of keeping data in memory in a separate process, it writes data to a table in the relational database the application already uses.

Solid Cable replaces the Redis adapter for Action Cable, used to distribute WebSocket messages between processes. By default, messages are retained in the database for one day, which also provides a pubsub history that Redis, being purely volatile memory, never offered.

What the configuration looks like in an existing app

For a Rails 7.2 app (the upgrade guide recommends going through this version before moving to 8.0), migration starts with the Gemfiles and the install generators:

ruby
# Gemfile
gem "solid_queue"
gem "solid_cache"
gem "solid_cable"
bash
bin/rails solid_queue:install
bin/rails solid_cache:install
bin/rails solid_cable:install
bin/rails db:migrate

Then, swap the adapters in config/environments/production.rb:

ruby
config.active_job.queue_adapter = :solid_queue
config.cache_store = :solid_cache_store
config.action_cable.adapter = :solid_cable

One point worth considering: if the Solid Queue, Solid Cache, and Solid Cable tables stay in the same database as the application, that can become a bottleneck in production, since every processed job and every cache read turns into a query competing with the application's normal traffic. That's why it makes sense to use the multiple-database configuration that Rails 8 already supports, to separate that load:

Official Rails documentation page about multiple databases, showing the chapter index and an example configuration of the database.yml file
Official Rails documentation page about multiple databases, showing the chapter index and an example configuration of the database.yml file. Reprodução: guides.rubyonrails.org.
yaml
# config/database.yml
production:
  primary:
    <<: *default
    database: app_production
  queue:
    <<: *default
    database: app_production_queue
    migrations_paths: db/queue_migrate
  cache:
    <<: *default
    database: app_production_cache
    migrations_paths: db/cache_migrate
  cable:
    <<: *default
    database: app_production_cable
    migrations_paths: db/cable_migrate

With this, the application's primary database doesn't compete with queue, cache, and pubsub for I/O and locks. It's the equivalent, in spirit, of having Redis separate from Postgres, except all three extra databases can run on the same Postgres or MySQL instance, without needing another database engine.

When the Solid trio still doesn't replace Sidekiq + Redis

Here's the point the announcement doesn't sell: Solid Queue solves the common case, but it isn't a 1:1 substitute for Sidekiq in every situation. The core difference is database polling mechanism versus in-memory queue.

FeatureSolid QueueSidekiq + RedisResque/Delayed Job
Extra infrastructureNone (uses the existing database)RedisRedis (or database, in Delayed Job)
Queuing mechanismDatabase-based (polling with FOR UPDATE SKIP LOCKED)In-memory queue (Redis)Database-based or Redis
Native rate limiting and uniquenessPartial, via its own configurationAdditional features in paid tiers (Pro/Enterprise)Limited
Queuing latencyDepends on the database (tends to be higher than in-memory)In-memory, tends to be lowerDepends on the database
Built-in observabilityNot documented in the official Rails 8 release notesSidekiq Web, Sidekiq ProBasic

In short: if the application runs on a well-sized database instance and doesn't depend on paid Sidekiq Pro features (batches, distributed uniqueness, advanced rate limiting), Solid Queue covers the case painlessly. If the queue is the heart of a system with a very high volume of events, or if the team already pays for Sidekiq Enterprise for a concrete reason, the switch still isn't worth it.

The same reasoning applies to Solid Cache: caching in a relational database tends to have higher read latency than in-memory Redis, even with well-designed indexes. For page fragments that change rarely, the difference is imperceptible. For very high-frequency read caching, such as a view counter updated on every request, Redis remains the more predictable choice.

For anyone deciding to migrate a production app, the sequence that reduces risk is gradual, not a "big bang":

  1. Upgrade to Rails 7.2 first, running the full test suite and confirming nothing broke before touching 8.0, the Rails upgrade guide itself recommends this intermediate step.
  2. Add Solid Cache first, in parallel with the current cache, using a staging environment to compare hit rate and latency before switching in production.
  3. Migrate Solid Queue only afterward, starting with the least critical queues (transactional email delivery, for example) before delay-sensitive business queues.
  4. Leave Solid Cable for last, because switching the WebSocket adapter in production without a canary with a few minutes of overlap can drop active connections.

What this doesn't solve on its own

It's worth remembering that Redis doesn't disappear from the Rails ecosystem by decree: it remains the recommended option for anyone who needs aggressive rate limiting (via rack-attack with a Redis store), very large-scale shared sessions, or data structures like sorted sets that relational databases don't model well. Rails 8 also kept the Redis adapter available for anyone who wants to keep using it; nothing was removed, only the default for new apps changed.

The real gain, for most small and medium product teams, is operational: one less service to provision, update, and monitor, and a simpler infrastructure bill. For those who have already operated Redis for years without pain, the decision rule is simple: if there's no concrete reason to migrate today, there's no need to. The Solid trio is the right choice for anyone starting a new project or for anyone who was already unhappy with the operational cost of keeping Redis just for jobs and cache.

Translated from the Brazilian Portuguese original · Read the original