From 22e2370b359c6e8f3b01a82a8e45e1d50b86f191 Mon Sep 17 00:00:00 2001 From: "Andrey A." <56412611+aantti@users.noreply.github.com> Date: Fri, 21 Aug 2026 15:10:18 +0200 Subject: [PATCH] docs(self-hosted): add poolers how-to guide (#49303) --- .../NavigationMenu.constants.ts | 1 + .../guides/api/rest/generating-types.mdx | 2 +- .../self-hosting/accessing-postgres.mdx | 128 ++++++++++++++++++ .../content/guides/self-hosting/docker.mdx | 59 +------- .../self-hosting/restore-from-platform.mdx | 4 +- .../steps/direct-connection/content.tsx | 2 +- docker/.env.example | 4 +- 7 files changed, 136 insertions(+), 64 deletions(-) create mode 100644 apps/docs/content/guides/self-hosting/accessing-postgres.mdx diff --git a/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts b/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts index 5498aca968b..f71fa59142a 100644 --- a/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts +++ b/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts @@ -3092,6 +3092,7 @@ export const self_hosting: NavMenuConstant = { items: [ { name: 'Overview', url: '/guides/self-hosting' }, { name: 'Deploy with Docker', url: '/guides/self-hosting/docker' }, + { name: 'Accessing Postgres', url: '/guides/self-hosting/accessing-postgres' }, { name: 'Configure new API keys', url: '/guides/self-hosting/self-hosted-auth-keys' }, { name: 'Learn about API Gateway', url: '/guides/self-hosting/self-hosted-envoy' }, { diff --git a/apps/docs/content/guides/api/rest/generating-types.mdx b/apps/docs/content/guides/api/rest/generating-types.mdx index c728c698795..64762769bc4 100644 --- a/apps/docs/content/guides/api/rest/generating-types.mdx +++ b/apps/docs/content/guides/api/rest/generating-types.mdx @@ -46,7 +46,7 @@ or in case of local development: npx supabase gen types typescript --local > database.types.ts ``` -or in case of a self-hosted instance (see [Accessing Postgres](/docs/guides/self-hosting/docker#accessing-postgres) for more information): +or in case of a self-hosted instance (see [Accessing Postgres](/docs/guides/self-hosting/accessing-postgres#connect-through-supavisor) for more information): ```bash npx supabase gen types typescript --db-url postgres://postgres.[POOLER_TENANT_ID]:[POSTGRES_PASSWORD]@[your-domain-or-ip]:5432/postgres --schema public > database.types.ts diff --git a/apps/docs/content/guides/self-hosting/accessing-postgres.mdx b/apps/docs/content/guides/self-hosting/accessing-postgres.mdx new file mode 100644 index 00000000000..c8113d9ce57 --- /dev/null +++ b/apps/docs/content/guides/self-hosting/accessing-postgres.mdx @@ -0,0 +1,128 @@ +--- +title: 'Accessing Postgres' +description: 'Connect to your self-hosted Postgres database through the Supavisor or PgBouncer pooler, or with a direct connection.' +subtitle: 'Connect to your self-hosted Postgres database through the Supavisor or PgBouncer pooler, or with a direct connection.' +--- + +This guide explains how to connect to Postgres in self-hosted Supabase, using the Supavisor pooler, the optional PgBouncer pooler, or a direct connection. + +Self-hosted Supabase uses [Supavisor](https://github.com/supabase/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 Supabase offers three ways to reach Postgres: + +- **Session mode** - Supavisor on port `5432`. Best for persistent clients that need per-session features such as `SET` statements, 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](#use-pgbouncer-instead-of-supavisor). Available by default. +- **Direct connection** - Postgres bypassing the pooler. Not exposed by default - refer to [exposing Postgres](#expose-postgres-for-direct-connections). 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: + +```sh +psql 'postgres://postgres.[POOLER_TENANT_ID]:[POSTGRES_PASSWORD]@[your-domain]:5432/postgres' +``` + +For transaction-mode connections: + +```sh +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: + +```sh +docker compose exec db psql -U postgres -c "SHOW max_connections;" +``` + +To change `max_connections` or other Postgres settings, refer to [custom Postgres configuration](/docs/guides/self-hosting/postgres-upgrade-17#custom-postgres-configuration). + +For the full list of Supavisor's configurable environment variables, check the reference list in [docker/CONFIG.md](https://github.com/supabase/supabase/blob/master/docker/CONFIG.md#supavisor). + +## Use PgBouncer instead of Supavisor + +Self-hosted Supabase includes an optional [PgBouncer](https://www.pgbouncer.org/) override. It disables Supavisor and runs PgBouncer in transaction mode on `POOLER_PROXY_PORT_TRANSACTION`. + +Add it to your stack with `run.sh`: + +```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`: + +```sh +# 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](#expose-postgres-for-direct-connections). 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. + + + +Exposing Postgres opens your database to the network. Configure firewall rules or network policies to restrict access to Postgres. + + + +If you use the default Supavisor stack, edit `docker-compose.yml`: + +1. Disable Supavisor by commenting out or removing the entire `supavisor` service section. +2. Expose the Postgres port by adding the port mapping to the `db` service: + +```yaml name=docker-compose.yml +db: + ports: + - ${POSTGRES_PORT}:${POSTGRES_PORT} + container_name: supabase-db +``` + + + +If you want to keep Supavisor running alongside a direct connection, map Postgres to a different host port (for example, `5433:${POSTGRES_PORT}`) instead of disabling Supavisor. + + + +If you use the PgBouncer override, Supavisor is already disabled. Uncomment the `db` block in `docker-compose.pgbouncer.yml` instead: + +```yaml name=docker-compose.pgbouncer.yml +db: + ports: + - ${POSTGRES_PORT}:${POSTGRES_PORT} +``` + +After restarting, connect directly with a standard Postgres connection string: + +```sh +postgres://postgres:[POSTGRES_PASSWORD]@[your-server-ip]:5432/[POSTGRES_DB] +``` + +## Additional resources + +- [Supavisor documentation](https://supabase.github.io/supavisor/development/docs/) +- [PgBouncer documentation](https://www.pgbouncer.org/config.html) +- [Connect to your database](/docs/guides/database/connecting-to-postgres) diff --git a/apps/docs/content/guides/self-hosting/docker.mdx b/apps/docs/content/guides/self-hosting/docker.mdx index dcbeddf3a5f..6b17aced1e4 100644 --- a/apps/docs/content/guides/self-hosting/docker.mdx +++ b/apps/docs/content/guides/self-hosting/docker.mdx @@ -319,27 +319,7 @@ You will be prompted for a username and password. See the [Studio authentication ## Accessing Postgres -The self-hosted Supabase stack provides the [Supavisor](https://supabase.github.io/supavisor/development/docs/) connection pooler for accessing Postgres and managing database connections. - -You can connect to the Postgres database via Supavisor using the methods described below. Use your domain name, your server IP, or `localhost` depending on whether you are running self-hosted Supabase on a VPS, or locally. - -The default `POOLER_TENANT_ID` is `your-tenant-id` (can be later changed in `.env`), and the password is the value of `POSTGRES_PASSWORD` from the `.env` file. - -For session-mode connections (equivalent to a direct Postgres connection): - -```sh -psql 'postgres://postgres.[POOLER_TENANT_ID]:[POSTGRES_PASSWORD]@[your-domain]:5432/postgres' -``` - -For transaction-mode connections: - -```sh -psql 'postgres://postgres.[POOLER_TENANT_ID]:[POSTGRES_PASSWORD]@[your-domain]:6543/postgres' -``` - -When using `psql` with command-line parameters instead of a connection string to connect to Supavisor, the `-U` parameter should also be `postgres.[POOLER_TENANT_ID]`. - -If you need to configure Postgres to be directly accessible from the Internet, read [Exposing your Postgres database](#exposing-your-postgres-database). +Self-hosted Supabase pools Postgres connections through Supavisor by default, with an optional PgBouncer pooler and a direct-connection option. For connection strings, pooler configuration, switching poolers, and exposing Postgres directly, see [Accessing Postgres](/docs/guides/self-hosting/accessing-postgres). To change the database password, read [Changing database password](#changing-database-password). @@ -590,43 +570,6 @@ By default, the Storage backend uses local files via a bind mount. On macOS, Doc Configuring the Supabase AI Assistant is optional. By adding **your own** `OPENAI_API_KEY` to `.env` you can enable AI services, which help with writing SQL queries, statements, and policies. -### Accessing Postgres through Supavisor - -By default, Postgres connections go through the Supavisor connection pooler for efficient connection management. Two ports are available: - -- `POSTGRES_PORT` (default: 5432) - Session mode, behaves like a direct Postgres connection -- `POOLER_PROXY_PORT_TRANSACTION` (default: 6543) - Transaction mode, uses connection pooling - -For more information on configuring and using Supavisor, see the [Supavisor documentation](https://supabase.github.io/supavisor/). - -### Exposing your Postgres database - -By default, Postgres is only accessible through Supavisor. If you need direct access to the database (bypassing the connection pooler), you need to disable Supavisor and expose the Postgres port. - - - - Exposing Postgres directly bypasses connection pooling and exposes your database to the network. Configure firewall rules or network policies to restrict access to trusted IPs only. - - - -Edit `docker-compose.yml`: - -1. **Disable Supavisor** - Comment out or remove the entire `supavisor` service section -2. **Expose Postgres port** - Add the port mapping to the `db` service, it should look like the example below: - -```yaml name=docker-compose.yml -db: - ports: - - ${POSTGRES_PORT}:${POSTGRES_PORT} - container_name: supabase-db -``` - -After restarting, you can connect to the database directly using a standard Postgres connection string: - -```sh -postgres://postgres:[POSTGRES_PASSWORD]@[your-server-ip]:5432/[POSTGRES_DB] -``` - ### Setting log_min_messages in Postgres By default, the database's `log_min_messages` configuration is set to `fatal` in [docker-compose.yml](https://github.com/supabase/supabase/blob/df8729a82b1847e2989c14ede27965612761d503/docker/docker-compose.yml#L466) to prevent redundant logs generated by Realtime. You can configure `log_min_messages` using any of the Postgres [Severity Levels](https://www.postgresql.org/docs/current/runtime-config-logging.html#RUNTIME-CONFIG-SEVERITY-LEVELS). diff --git a/apps/docs/content/guides/self-hosting/restore-from-platform.mdx b/apps/docs/content/guides/self-hosting/restore-from-platform.mdx index b0ccb621174..f13530e00ae 100644 --- a/apps/docs/content/guides/self-hosting/restore-from-platform.mdx +++ b/apps/docs/content/guides/self-hosting/restore-from-platform.mdx @@ -52,7 +52,7 @@ Before restoring, check the following on your self-hosted instance: ## Step 4: Restore to your self-hosted database -Connect to your self-hosted Postgres and restore the dump files. The [default](/docs/guides/self-hosting/docker#accessing-postgres) connection string for self-hosted Supabase is: +Connect to your self-hosted Postgres and restore the dump files. The [default](/docs/guides/self-hosting/accessing-postgres#connect-through-supavisor) connection string for self-hosted Supabase is: ``` postgres://postgres.your-tenant-id:[POSTGRES_PASSWORD]@[your-domain]:5432/postgres @@ -166,7 +166,7 @@ select * from pg_available_extensions; ### Connection refused -Make sure your self-hosted Postgres port is accessible. In the default [self-hosted Supabase](/docs/guides/self-hosting/docker#accessing-postgres) setup, the user is `postgres.your-tenant-id` with Supavisor on port `5432`. +Make sure your self-hosted Postgres port is accessible. In the default [self-hosted Supabase](/docs/guides/self-hosting/accessing-postgres#connect-through-supavisor) setup, the user is `postgres.your-tenant-id` with Supavisor on port `5432`. ### Legacy Studio configuration diff --git a/apps/studio/components/interfaces/ConnectSheet/content/steps/direct-connection/content.tsx b/apps/studio/components/interfaces/ConnectSheet/content/steps/direct-connection/content.tsx index d6d3dc3c130..b7ab7b99d61 100644 --- a/apps/studio/components/interfaces/ConnectSheet/content/steps/direct-connection/content.tsx +++ b/apps/studio/components/interfaces/ConnectSheet/content/steps/direct-connection/content.tsx @@ -286,7 +286,7 @@ function DirectConnectionContent({ state, deploymentMode }: StepContentProps) {

Manually{' '} configurable {' '} diff --git a/docker/.env.example b/docker/.env.example index 997b20e6482..4f03214f1e7 100644 --- a/docker/.env.example +++ b/docker/.env.example @@ -114,7 +114,7 @@ POSTGRES_DB=postgres # Default configuration includes Supavisor exposing POSTGRES_PORT # Postgres uses POSTGRES_PORT inside the container # Documentation: -# https://supabase.com/docs/guides/self-hosting/docker#accessing-postgres-through-supavisor +# https://supabase.com/docs/guides/self-hosting/accessing-postgres POSTGRES_PORT=5432 @@ -141,7 +141,7 @@ POOLER_MAX_CLIENT_CONN=100 # Unique Supavisor tenant identifier # Documentation: -# https://supabase.com/docs/guides/self-hosting/docker#accessing-postgres +# https://supabase.com/docs/guides/self-hosting/accessing-postgres POOLER_TENANT_ID=your-tenant-id # Pool size for internal metadata storage used by Supavisor