To deploy a Rails app with Postgres to a server you have ssh access to using Kamal, start with what the Rails app needs to connect to the db: POSTGRES_USER POSTGRES_PASSWORD DB_HOST POSTGRES_DB. These env vars are used in config/database.yml like this:

production:
  primary: &primary_production
    <<: *default
    username: <%= ENV['POSTGRES_USER'] %>
    password: <%= ENV['POSTGRES_PASSWORD'] %>
    host: <%= ENV['DB_HOST'] %>
    port: <%= ENV.fetch('DB_PORT', 5432) %>
    database: <%= ENV['POSTGRES_DB'] %>

The POSTGRES_ env vars are named that way for the postgres docker image.

Add the accessory

In the accessories section of config/deploy.yml, add a postgres database:

accessories:
  db:
    image: postgres:18.3
    host: <server ip>
    env:
      clear:
        POSTGRES_DB: my_app_production
        POSTGRES_USER: my_app
      secret:
        - POSTGRES_PASSWORD
    directories:
      - data:/var/lib/postgresql

Here, the env vars control how the postgres image is configured. Check the official postgres docker image docs for more info. The value of POSTGRES_PASSWORD comes from .kamal/secrets.

App container env

With the db accessory configured, give the app container the env vars it needs:

service: my_app
# ...
env:
  secret:
    - POSTGRES_PASSWORD
  clear:
    POSTGRES_USER: my_app
    DB_HOST: my_app-db
    POSTGRES_DB: my_app_production

POSTGRES_PASSWORD comes from the same secret that the db accessory has. POSTGRES_USER and POSTGRES_DB are also copied over. DB_HOST is a value that comes from Kamal. By default, it’s the combination of the service name and the postgres accessory key separated by a dash(docker container network).

With that, boot the db accessory then deploy the application.