Rails 8 Multiple Databases on Heroku

Rails 8 introduced support for multiple databases, and by default, it wants to create separate database instances for your primary data, cache, queue, and ActionCable connections. If you’re deploying to Heroku and you just follow the defaults, you’ll end up with four separate Postgres databases, which means four separate billable databases instances.

I’m using a single database instead. Here’s why, and when you might actually want separate databases.

The Default Rails 8 Configuration

When you set up Rails 8 with SolidQueue, SolidCache, and ActionCable, the default database.yml looks something like this:

production:
  primary:
    url: <%= ENV["DATABASE_URL"] %>
  cache:
    url: <%= ENV["CACHE_DATABASE_URL"] %>  # Different database!
  queue:
    url: <%= ENV["QUEUE_DATABASE_URL"] %>  # Different database!
  cable:
    url: <%= ENV["CABLE_DATABASE_URL"] %>  # Different database!

If you deploy this to Heroku without setting those environment variables, Rails will try to create separate databases. On Heroku, that means four separate Postgres add-ons, which gets expensive fast.

Our Configuration: One Database, Multiple Connections

Instead, we can point everything at the same database:

production:
  primary: &primary_production
    <<: *default
    database: seeress_production
    url: <%= ENV["DATABASE_URL"] %>
  cache:
    <<: *primary_production
    url: <%= ENV["DATABASE_URL"] %>  # Same database
    migrations_paths: db/cache_migrate
  queue:
    <<: *primary_production
    url: <%= ENV["DATABASE_URL"] %>  # Same database
    migrations_paths: db/queue_migrate
    pool: <%= ENV.fetch("SOLID_QUEUE_POOL", 5).to_i %>
  cable:
    <<: *primary_production
    url: <%= ENV["DATABASE_URL"] %>  # Same database
    migrations_paths: db/cable_migrate

All four logical connections point to the same physical database. You still get the benefits of logical separation (different migration paths, different connection pools), but you’re only paying for one database instance.

Why Rails 8 Does This By Default

Before I decided to use one database, I had to understand why Rails 8 wants separate databases in the first place. Rails 8 defaults to separate databases for a few good reasons:

  1. Isolation – If your cache database gets hammered, it doesn’t affect your primary queries
  2. Scaling – You can scale cache/queue databases independently from your primary data
  3. Backup strategies – You might want different backup schedules for different data types
  4. Multi-tenant setups – Some apps need separate databases per tenant

These are all valid reasons, but they don’t apply to my smaller app scale use-case.

When Separate Databases Make Sense

You will want separate databases if…

  • You’re running at scale – If you’re processing millions of jobs per day, a separate queue database might make sense
  • You have different performance requirements. -Cache databases can use different instance types optimized for read-heavy workloads
  • You need geographic distribution – You might want your cache database in a different region than your primary
  • You’re doing multi-tenant – Each tenant gets their own database
  • You have compliance requirements – Some data might need to be in a separate, more secure database

For most apps, especially ones running on Heroku’s managed Postgres, these concerns don’t apply. I am a big fan of Heroku for this and many other reasons.

Why One Rails 8 Database Works on Heroku

Heroku’s Postgres handles I/O pretty well. The connection pooling works fine, and I’m not at a scale where we need to separate cache from primary data. My queue tables are small, cache tables are small, and they all live happily together in the same database.

The key is that we still get logical separation:

  • Different migration paths (db/migratedb/cache_migratedb/queue_migratedb/cable_migrate)
  • Different connection pools (we can tune the queue pool separately)
  • Different ActiveRecord models (SolidQueue::Job, SolidCache::Entry, etc.)

There hasn’t be an issue with throughput at the database for me in this, or in many of my Rails apps on Heroku. If scaling becomes a need, it’s a quick config and database migration task away from being ready.

The Cost Difference

On Heroku, a Hobby Dev Postgres database is $5/month. If you follow Rails 8 defaults and create four databases, that’s $20/month just for databases. For a small app, that’s unnecessary.

Even on Standard plans, you’re looking at $50/month per database. Four databases = $200/month. One database = $50/month.

Unless you actually need the isolation, you’re just burning money.

How We Deploy

When we deploy to Heroku, we only provision one database:

heroku addons:create heroku-postgresql:standard-0

This gives us DATABASE_URL, and we point everything at it. Migrations still work correctly:

rails db:migrate              # Primary tables
rails db:migrate:cache        # SolidCache tables
rails db:migrate:queue        # SolidQueue tables  
rails db:migrate:cable        # ActionCable tables

Each migration path creates its own tables in the same database. SolidQueue tables don’t conflict with SolidCache tables because they’re in different namespaces.

When to Reconsider Multiple Rails 8 Databases on Heroku

There are 3 key triggers for me to move to separate databases:

  1. We hit performance issues: If cache queries start affecting primary queries, we’d split them
  2. We need to scale independently: If the queue database needs more resources than the primary
  3. We outgrow Heroku’s single-database approach: If we need geographic distribution or specialized instances

But right now, the need is not there. One database works fine, and it saves money while prototyping and even in many of my production apps.

The Bottom Line

Rails 8 multiple database support is great, but the default configuration assumes you need physical separation. For most apps on Heroku, you don’t.

If you need separate databases later, you can always split them. If you are just prototyping or running a smaller app you can start with one, and only add more when you have a real reason.

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Sign In

Register

Reset Password

Please enter your username or email address, you will receive a link to create a new password via email.