Hosts

Use a direct connection

Tablebelt speaks the Postgres wire protocol. Transaction-mode poolers drop session state and prepared statements. tablebelt doctor warns when it sees one. Use the direct or session endpoint. IAM token auth for RDS is not in this version: use a password role.

Roles

One proxy process fronts one database. tablebelt_agent is the upstream role for agent traffic. tablebelt_admin owns schema tablebelt and runs snapshots and restore. If you skip a separate admin DSN, the upstream DSN does both, and the agent role must not be able to write the snapshot schema. The classifier also denies anything that touches schema tablebelt, and that deny cannot be overridden.

roles
-- Printed again by: tablebelt init --print-roles
CREATE ROLE tablebelt_agent LOGIN PASSWORD 'replace-me';
CREATE ROLE tablebelt_admin LOGIN PASSWORD 'replace-me';

-- Agent traffic. DML and DDL on the app schema, as you choose.
-- No membership in admin roles. No privileges on schema tablebelt.
GRANT CONNECT ON DATABASE app TO tablebelt_agent;
GRANT USAGE, CREATE ON SCHEMA public TO tablebelt_agent;
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO tablebelt_agent;
ALTER DEFAULT PRIVILEGES IN SCHEMA public
  GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO tablebelt_agent;

-- Snapshots and restore. SELECT on app tables, plus ownership of
-- (or membership in the owner of) the tables it restores.
GRANT CONNECT ON DATABASE app TO tablebelt_admin;
GRANT USAGE ON SCHEMA public TO tablebelt_admin;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO tablebelt_admin;

DigitalOcean

Use the direct connection on port 25060 with sslmode=require, not the connection pool. tablebelt init prints which TLS mode it chose. Download the DigitalOcean CA bundle if you want sslmode=verify-full.

RDS

Use a password role in the upstream DSN. IAM token auth is not in this version. For verify-full, use the Amazon RDS CA bundle (sslrootcert). Do not point the agent at the RDS endpoint.

Neon

Use the host without -pooler. The pooled host is transaction mode and breaks session state. TLS is required.

Railway

Use the external URL with TLS, not an internal URL the proxy host cannot resolve. Keep that URL in TABLEBELT_UPSTREAM_DSN on the proxy host.

Supabase

Use the direct or session connection on port 5432. Do not use the transaction pooler on port 6543. Session mode keeps prepared statements and search_path.

Render

Use the external database URL with TLS. The internal URL is only reachable inside Render's network. If the proxy runs elsewhere, the external URL is the one that works.

Self-hosted

Point TABLEBELT_UPSTREAM_DSN at Postgres. Prefer sslmode=verify-full when the proxy and the database are on different hosts, and sslmode=disable only for a local socket or loopback. Restrict pg_hba.conf so tablebelt_agent is reachable from the proxy host and not from the agent host.

Other

Any host that gives you a normal Postgres connection string works. If the only endpoint is a transaction pooler, Tablebelt will mis-handle session state. Ask the host for a direct or session port. If you are not sure, pick other on the signup form and run tablebelt doctor after init.