When you deploy a fresh Rails 8 app with the Solid “trifecta” (Solid Cache, Solid Queue, Solid Cable), you actually have four database connections in production: primary, cache, queue, and cable. If only `DATABASE_URL` is set, the other three try to connect via the default local socket and you’ll see:
bin/rails aborted!
ActiveRecord::ConnectionNotEstablished: connection to server on socket "/var/run/postgresql/.s.PGSQL.5432" failed: No such file or directory
...
Tasks: TOP => db:prepare
The fix is to explicitly configure all Solid DBs and run their migrations.
1) Wire up all four database URLs
Use distinct URLs, or point them all to the same Postgres if that’s fine for your scale.
config/database.yml (production)
production:
primary:
url: <%= ENV["PRIMARY_DATABASE_URL"] || ENV["DATABASE_URL"] %>
cache:
url: <%= ENV["CACHE_DATABASE_URL"] || ENV["DATABASE_URL"] %>
migrations_paths: db/cache_migrate
queue:
url: <%= ENV["QUEUE_DATABASE_URL"] || ENV["DATABASE_URL"] %>
migrations_paths: db/queue_migrate
cable:
url: <%= ENV["CABLE_DATABASE_URL"] || ENV["DATABASE_URL"] %>
Rails 8 treats cache/queue/cable as separate DB configs; providing CACHE_DATABASE_URL, QUEUE_DATABASE_URL, and CABLE_DATABASE_URL (or falling back to DATABASE_URL) prevents the “local socket” miss.
Kamal deploy.yml snippet:
env:
clear:
RAILS_ENV: production
secret:
- DATABASE_URL
- PRIMARY_DATABASE_URL
- CACHE_DATABASE_URL
- QUEUE_DATABASE_URL
- CABLE_DATABASE_URL
(If you’re running a Postgres accessory with Kamal, ensure these URLs point at that service, not a local socket.)
2) Install Solid components (if not already)
These tasks create the right schema/migration paths.
bin/rails solid_cache:install
bin/rails solid_queue:install
bin/rails solid_cable:install
- Cache/Queue create migration paths under
db/cache_migrateanddb/queue_migrate. - Cable creates
db/cable_schema.rband requires a DB entry.
3) Commit a migration for cache/queue (don’t rely only on schema dumps)
Add an explicit migration under each path so db:prepare can apply them in production:
bin/rails g migration InitSolidCache --migration_path=db/cache_migrate
bin/rails g migration InitSolidQueue --migration_path=db/queue_migrate
Paste the table definitions from your local generated schema files (or re-run the install tasks locally and copy the structure). Then:
bin/rails db:prepare
This guarantees the cache and queue tables exist in the target DB(s), just like your primary.
4) (Option) Keep it simple: one Postgres for all four
For small apps, it’s perfectly fine to point primary, cache, queue, and cable to the same Postgres and split them out later as load grows. Update the four entries in database.yml to all use ENV["DATABASE_URL"].
Why this happens
Rails 8 defaults to multi-DB for Solid Cache/Queue/Cable. PaaS/Kamal setups commonly only export DATABASE_URL. Without explicit URLs, the Solid DBs fall back to a local socket path (/var/run/postgresql/...), which doesn’t exist in your container, hence ConnectionNotEstablished. Setting *_DATABASE_URL (or wiring database.yml to reuse DATABASE_URL) aligns all four connections with your actual Postgres.
Quick Checklist (made by AI)
[ ] database.yml has primary/cache/queue/cable with URLs
[ ] Env has CACHE_DATABASE_URL, QUEUE_DATABASE_URL, CABLE_DATABASE_URL (or they fall back to DATABASE_URL)
[ ] Ran solid_cache:install, solid_queue:install, solid_cable:install
[ ] Created/committed migrations under db/cache_migrate and db/queue_migrate * [ ] bin/rails db:prepare succeeds in the deploy container
After this, Kamal deploys should boot cleanly without the Postgres socket error, and Hotwire/Action Cable plus jobs and cache will work as expected.