Running Rails 8 Solid Cache, Queue & Cable on Heroku with Multiple Databases
Rails 8 ships with the Solid trifecta:
-
Solid Cache durable, DB-backed cache store
-
Solid Queue jobs without Redis
-
Solid Cable Action Cable on Postgres
Together, they let you drop Redis entirely and run your whole stack on Postgres. Perfect for Heroku… but there are a few gotchas if you want to isolate each component into its own database.
This article shows how I set up Rails 8 + Heroku with:
-
Primary DB → app data + jobs (Solid Queue) + websockets (Solid Cable)
-
Cache DB → Solid Cache (kept separate to avoid bloat) (but you can run on 3 different DB)
Why multiple databases?
Solid’s docs suggest splitting out Cache/Queue/Cable into separate DBs. On Heroku you can start simple (1 DB for everything), but caches tend to churn. If you expect lots of API hits or domain-level caching, isolating Solid Cache is cheap insurance:
-
Primary stays lean → your schema/migrations aren’t slowed by millions of cache rows.
-
Cache is disposable → you can drop & recreate it without touching app data.
-
Scaling knobs → you can upgrade just the cache DB if needed.
Database.yml setup
Rails already wires up multi-DB. In production, switch to url: so Heroku env vars work:
production:
primary:
<<: *default
url: <%= ENV["DATABASE_URL"] %>
cache:
<<: *default
url: <%= ENV["CACHE_DATABASE_URL"] || ENV["DATABASE_URL"] %>
migrations_paths: db/cache_migrate
queue:
<<: *default
url: <%= ENV["DATABASE_URL"] %>
migrations_paths: db/queue_migrate
cable:
<<: *default
url: <%= ENV["DATABASE_URL"] %>
migrations_paths: db/cable_migrate
Cache.yml
Rails tells Solid Cache which DB to use via config/cache.yml:
production:
database: cache
store_options:
namespace: production
Don’t duplicate the config in production.rb. Just:
# config/environments/production.rb
config.cache_store = :solid_cache_store
That’s it. Solid will pick up the cache connection from cache.yml.
Installing the schemas
Solid creates db/cache_schema.rb, db/queue_schema.rb, db/cable_schema.rb.
Put each into its own migration folder:
- db/cache_migrate/init_solid_cache.rb
- db/queue_migrate/init_solid_queue.rb
- db/cable_migrate/init_solid_cable.rb
Each migration just loads the schema:
class InitSolidCache < ActiveRecord::Migration[8.0]
def up
load Rails.root.join("db/cache_schema.rb")
end
def down = raise ActiveRecord::IrreversibleMigration
end
Rails knows which DB to run it against based on the folder.
Run once:
bin/rails db:migrate
All four DBs (primary + cache + queue + cable) will be created and seeded.
Heroku setup
Provision two Postgres add-ons:
heroku addons:create heroku-postgresql:essential-0 # primary
heroku addons:create heroku-postgresql:essential-0 # cache
Alias the second one:
heroku config:set CACHE_DATABASE_URL=$(heroku config:get HEROKU_POSTGRESQL_BLUE_URL)
Deploy + migrate:
git push heroku main
heroku run rails db:migrate
Smoke tests
Cache write/read in your heroku console
Rails.cache.write("smoke:key","ok",expires_in:60)
puts Rails.cache.read("smoke:key")
Queue enqueue:
ApplicationJob.perform_later("smoke") # should see the job run (if SOLID_QUEUE_IN_PUMA=1)
Cleanup job (recommended)
Caches grow. Add a nightly cleanup to delete expired entries
Lessons learned
- Don’t duplicate config: pick cache.yml or production.rb for Solid Cache, not both.
- Each schema file lives in its own db/*_migrate folder → Rails handles connections.
- Add test.cache/queue/cable entries in database.yml to avoid KeyErrors in dev.
- Start with 1 DB if you’re unsure. Splitting out cache is a 5-minute change later.
Pricing
each DB costs 10$/month on Heroku so make sure you need it ;)