This guide explains how to connect to Postgres in self-hosted Zuvo, using the Supavisor pooler, the optional PgBouncer pooler, or a direct connection.
Self-hosted Zuvo uses Supavisor as its default connection pooler. A pooler sits in front of Postgres and shares a small set of database connections across many clients, which avoids exhausting Postgres connection limits.
Choose a connection mode
Self-hosted Zuvo offers three ways to reach Postgres:
- Session mode - Supavisor on port
5432. Best for persistent clients that need per-session features such asSETstatements, prepared statements,LISTEN/NOTIFY, or advisory locks. Each client holds a dedicated Postgres connection for the life of the session. Available by default. - Transaction mode - Supavisor or PgBouncer on port
6543. Best for serverless or edge functions that open many short-lived connections. Does not support session-level features (SET,LISTEN/NOTIFY, temporary tables that span transactions, or advisory locks). Supavisor pooler does not support prepared statements; PgBouncer can be configured to support them. Available by default. - Direct connection - Postgres bypassing the pooler. Not exposed by default - refer to exposing Postgres. Best for migrations,
pg_dump, and long-lived backends.
Connect through Supavisor [#connect-through-supavisor]
Use your domain name, your server IP, or localhost, depending on where the stack runs.
For session-mode connections:
psql 'postgres://postgres.[POOLER_TENANT_ID]:[POSTGRES_PASSWORD]@[your-domain]:5432/postgres'
For transaction-mode connections:
psql 'postgres://postgres.[POOLER_TENANT_ID]:[POSTGRES_PASSWORD]@[your-domain]:6543/postgres'
Supavisor requires the "tenant ID" (your-tenant-id) for authentication, not only the role. When using psql with command-line parameters instead of a connection string, the -U parameter must also be postgres.[POOLER_TENANT_ID].
Customize Supavisor
Configure Supavisor settings through your .env file, then recreate the stack for changes to take effect:
| Variable | Default | Description |
|---|---|---|
POSTGRES_PORT | 5432 | Host port for session-mode connections. |
POOLER_PROXY_PORT_TRANSACTION | 6543 | Host port for transaction-mode connections. |
POOLER_DEFAULT_POOL_SIZE | 20 | Postgres connections the pooler opens per pool. Keep this below your Postgres max_connections minus connections reserved for other services. |
POOLER_MAX_CLIENT_CONN | 100 | Client connections the pooler accepts. |
POOLER_TENANT_ID | your-tenant-id | Supavisor tenant identifier, used in the username. |
POOLER_DB_POOL_SIZE | 5 | Internal metadata pool used by Supavisor itself. |
To check your current Postgres max_connections setting:
docker compose exec db psql -U postgres -c "SHOW max_connections;"
To change max_connections or other Postgres settings, refer to custom Postgres configuration.
For the full list of Supavisor's configurable environment variables, check the reference list in docker/CONFIG.md.
Use PgBouncer instead of Supavisor
Self-hosted Zuvo includes an optional PgBouncer override. It disables Supavisor and runs PgBouncer in transaction mode on POOLER_PROXY_PORT_TRANSACTION.
Add it to your stack with run.sh:
sh run.sh config add pgbouncer
sh run.sh start
If you prefer to run Docker Compose commands explicitly, use docker compose -f docker-compose.yml -f docker-compose.pgbouncer.yml up -d.
To connect as postgres:
# tenant ID isn't required for PgBouncer
psql 'postgres://postgres:[POSTGRES_PASSWORD]@[your-domain]:6543/postgres'
The PgBouncer override provides transaction mode only. For session-mode connections, or for features that transaction mode does not support (such as SET statements or LISTEN/NOTIFY), reconfigure PgBouncer manually by editing its environment variables in docker-compose.pgbouncer.yml, or use a direct connection. PgBouncer reuses the POOLER_DEFAULT_POOL_SIZE and POOLER_MAX_CLIENT_CONN values from your .env configuration.
Expose Postgres for direct connections
In the default configuration, Postgres is only reachable through the pooler. To bypass the pooler for migrations, pg_dump, or other direct-connection needs, expose the Postgres port.
If you use the default Supavisor stack, edit docker-compose.yml:
- Disable Supavisor by commenting out or removing the entire
supavisorservice section. - Expose the Postgres port by adding the port mapping to the
dbservice:
db:
ports:
- ${POSTGRES_PORT}:${POSTGRES_PORT}
container_name: supabase-db
If you use the PgBouncer override, Supavisor is already disabled. Uncomment the db block in docker-compose.pgbouncer.yml instead:
db:
ports:
- ${POSTGRES_PORT}:${POSTGRES_PORT}
After restarting, connect directly with a standard Postgres connection string:
postgres://postgres:[POSTGRES_PASSWORD]@[your-server-ip]:5432/[POSTGRES_DB]