Four databases, one application
Rails 8 ships with four databases configured by default, and most developers never notice, because the framework hides the seam almost completely.
What is configured
config/database.yml in this application declares four entries per environment:
development:
primary: ...
cache: { migrations_paths: db/cache_migrate }
queue: { migrations_paths: db/queue_migrate }
cable: { migrations_paths: db/cable_migrate }
Each one is a separate connection role with its own pool, its own schema and its own migration path. They aren't four connections to one thing. They're four databases you can address independently, which sometimes point at the same server.
The schemas are separate files, and their sizes tell you what each one is for:
| Schema file | Tables | Holds |
|---|---|---|
db/schema.rb |
33 | Courses, users, enrollments, submissions: the application |
db/queue_schema.rb |
11 | Solid Queue's jobs, executions, semaphores, processes |
db/cache_schema.rb |
1 | solid_cache_entries |
db/cable_schema.rb |
1 | solid_cable_messages |
flowchart TB
A["one Rails application"] --> P["primary role. 33 tables"]
A --> C["cache role. 1 table"]
A --> Q["queue role. 11 tables"]
A --> B["cable role. 1 table"]
P --> N["four pools, four schemas, four migration paths"]
C --> N
Q --> N
B --> N
Why Rails 8 did this
Each of those three used to be a separate service. A job queue meant Redis and Sidekiq. A cache meant Redis or Memcached. WebSockets meant Redis as a broker.
The Solid family replaced all three with tables, and support for multiple databases is what makes that bearable. The cache's million rows don't have to live in the same schema as your users, and clearing the queue doesn't mean touching application data.
The trade is worth stating plainly. You have one fewer service to run and one more concept to understand. For a small team that's usually a good trade, but only if the concept is understood, and that's what this course is for.
Logical separation is not physical separation
Everything else in this course rests on this distinction.
The four entries are always logically separate: separate pools, separate schema files, separate db:migrate:* tasks. Whether they're physically separate comes down to a string.
In this application's development environment they name four different databases. In production, three of them name the same one:
production:
primary: { database: app_production }
cache: { database: app_production_cache }
queue: { database: app_production }
cable: { database: app_production }
Changing where a role points is one line and no code, because nothing in the application refers to a database by name. It refers to a role. That property is the reason to use the feature, and lesson 5 covers the decision it makes cheap.
Key takeaways
- Rails 8 configures four databases by default: primary, cache, queue and cable.
- Each is a role with its own pool, schema file and migration path, with 33, 1, 11 and 1 tables here.
- The Solid family replaced Redis, Memcached and a WebSocket broker with tables in your own database.
- Logical separation is always there. Physical separation is whatever the
database:string says. - Nothing in the application names a database, only a role, so moving one is a one-line change.
Keep going with lesson 2
How a model finds its database
Models inherit primary, while Solid adapters use connects_to to name a role that database.yml resolves.
A free account also gives you the quizzes, your progress and notes, and the discussion.