Files
Filipe CabaçoandIvan Vasilov 29e47821f5 fix(realtime): add pg changes pool to realtime settings (#49256)
## I have read the
[CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md)
file.

YES

## What kind of change does this PR introduce?

Feature — adds a new Realtime setting to configure the Postgres Changes
connection pool size.

## What is the current behavior?

The Realtime settings page only exposes the connection pool used for
Realtime Authorization (`connection_pool`). The pool that Realtime uses
for Postgres Changes is not surfaced anywhere in the dashboard, so
projects that need to tune it have no self-serve way to do so — the only
option is to contact support.

## What is the new behavior?

The Realtime settings page now includes a **Postgres Changes connection
pool size** field:

- Reads `postgres_changes_pool` from the project's Realtime config,
falling back to a default of `2` when no override is stored.
- Validates input from `1` through `20` (`MAX_POSTGRES_CHANGES_POOL`),
and submits the value as a number in the config `PATCH` payload.
- Docs (`apps/docs/content/guides/realtime/settings.mdx`) are expanded
with sizing guidance for both connection pools, plus limits,
resource-usage notes, and the operational error codes to look for.

<img width="1160" height="166" alt="Screenshot 2026-08-19 at 13 59 04"
src="https://github.com/user-attachments/assets/fd3ee29e-e9bf-438b-970f-8008ec57020f"
/>

## Additional context

The named `RealtimeConfigResponse` / `UpdateRealtimeConfigBody` schemas
in the generated `api-types` package do not carry
`postgres_changes_pool` yet, so both the query and mutation types extend
the generated schema locally — the same pattern already used elsewhere
in `apps/studio/data/`. Once the platform OpenAPI spec ships the field
and `api-types` is regenerated, those two local intersections can be
dropped.

Covered by component tests in `RealtimeSettings.test.tsx` for both the
fetch and save paths.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Added a Realtime setting to configure the Postgres Changes connection
pool size.
  * Connection pools support 1–20 connections, with a default of 2.
  * Saving the setting now applies the configured value correctly.

* **Documentation**
* Expanded Realtime Settings guidance with configuration limits,
resource usage, channel access, payload and presence limits, plan
ceilings, spend-cap restrictions, and operational error codes.
* Added guidance for sizing authorization and Postgres Changes
connection pools.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Ivan Vasilov <vasilov.ivan@gmail.com>
2026-08-21 09:08:28 +01:00

111 lines
7.3 KiB
Plaintext

---
title: 'Settings'
description: 'Realtime Settings that allow you to configure your Realtime usage.'
subtitle: 'Realtime Settings that allow you to configure your Realtime usage.'
---
## Settings
<Admonition type="caution">
All changes made in this screen will disconnect all your connected clients to ensure Realtime starts with the appropriate settings and all changes are stored in Supabase middleware.
</Admonition>
<Image
alt="Usage page navigation bar"
src={{
light: '/docs/img/guides/platform/realtime/realtime-settings--light.png',
dark: '/docs/img/guides/platform/realtime/realtime-settings--dark.png',
}}
width={4600}
height={2600}
/>
You can set the following settings using the Realtime Settings screen in your Dashboard. For the ceilings your plan allows, see [Realtime Limits](/docs/guides/realtime/limits); the rate and payload limits are only editable while your organization's spend cap is disabled. For the errors below, see [Operational Error Codes](/docs/guides/realtime/error_codes).
### Enable Realtime service
**Type:** Toggle · **Options:** Enabled, Disabled · **Default:** Enabled
Determines if the Realtime service is enabled or disabled for your project.
- **Enabled**: normal operation.
- **Disabled**: connected clients are disconnected, new connections are rejected with `403` and `Realtime was disabled for this tenant`, joins receive `RealtimeDisabledForTenant`, and Broadcast REST requests are rejected with `403`. Realtime also releases the database connections and Postgres Changes replication slot it holds for your project, and reopens them on the first connection after you enable it again.
### Allow public access to channels
**Type:** Toggle · **Options:** Enabled, Disabled · **Default:** Enabled
Determines whether Realtime allows public channels, or restricts your project to private channels with [Realtime Authorization](/docs/guides/realtime/authorization).
- **Enabled**: no policy check runs, but anyone holding your project's anon key can subscribe to and broadcast on any public channel.
- **Disabled**: every join is checked against the Row Level Security policies on `realtime.messages`, so each join costs one authorization query. Clients that don't set `config.private` to `true` are rejected with `PrivateOnly`. With no policies, clients connect but receive no messages.
### Database connection pool size
**Type:** Number of connections · **Range:** 1 to your database's `max_connections` · **Default:** varies by compute size
Determines the number of connections used for Realtime Authorization RLS checking. Results are cached per client, so the pool is used on each private channel join, each `access_token` refresh, and each private Broadcast REST request.
- **Too low**: checks queue and time out. Clients receive `IncreaseConnectionPool`, broadcasts are dropped, and presence calls fail. Once timeouts in a 30-second window reach the pool size, later checks fail immediately without reaching the database.
- **Too high**: the pool competes with your application for your database's `max_connections`. If Realtime's total requirement doesn't fit, it refuses to start with `DatabaseLackOfConnections`.
See [Database connections](/docs/guides/realtime/concepts#database-connections) for the defaults per compute size.
### Postgres Changes connection pool size
**Type:** Number of connections · **Range:** 1 to 20 · **Default:** 2
Determines the number of connections used to create [Postgres Changes](/docs/guides/realtime/postgres-changes) subscriptions when clients subscribe. It's only used while subscriptions are created; streaming the changes uses a separate connection.
- **Too low**: subscription creation times out during bursts. Clients receive a `postgres_changes` system error with `Too many database timeouts` and retry after 5 to 10 seconds.
- **Too high**: it counts toward the same connection budget as every other Realtime pool.
Raise this value if many clients subscribe at the same time, such as after a deploy or a mass reconnect.
{/* supa-mdx-lint-disable-next-line Rule004ExcludeWords */}
### Max concurrent clients
**Type:** Number of clients · **Range:** 1 to your plan's [concurrent connections](/docs/guides/realtime/limits#limits-by-plan) limit · **Default:** your plan's limit
Determines the maximum number of clients that can be connected. A client is one WebSocket connection, no matter how many channels it joins.
- **Too low**: new connections are rejected with `429` and `Too many connected users`. Existing clients are unaffected.
- **Too high**: each connection consumes memory on the Realtime nodes, so this setting acts as a capacity and cost control.
### Max events per second
**Type:** Number of events per second · **Range:** 1 to your plan's [messages per second](/docs/guides/realtime/limits#limits-by-plan) limit · **Default:** your plan's limit
Determines the maximum number of events per second that can be sent, measured as a rolling average over the previous minute. An event is a message sent by a client or delivered to one, so one broadcast to 100 subscribers counts as 100 events.
- **Too low**: channels that exceed the average are closed with `Too many messages per second`, which `supabase-js` recovers from by rejoining. Broadcast REST requests are rejected with `429`; those responses carry `x-rate-limit` and `x-rate-limit-remaining` headers you can use to slow down first.
- **Too high**: Realtime stops throttling broadcast fan-out, which removes the protection against a runaway loop or a mass reconnect, and raises the ceiling on your Realtime spend.
### Max presence events per second
**Type:** Number of events per second · **Range:** 1 to your plan's [presence messages per second](/docs/guides/realtime/limits#limits-by-plan) limit · **Default:** your plan's limit
Determines the maximum number of presence events per second that can be sent, using the same rolling average as [Max events per second](#max-events-per-second) but checked before the event is sent rather than after delivery.
- **Too low**: presence tracking and syncing fail and the channel is closed with `Too many presence messages per second`.
- **Too high**: rapid `track` and `untrack` cycles can generate presence storms, because each change is broadcast to every client on the channel and also counts toward [Max events per second](#max-events-per-second).
<Admonition type="note">
A separate per-client limit also applies to presence, independent of this project-wide setting. A client that exceeds it is closed with `Client presence rate limit exceeded`. See [Realtime Limits](/docs/guides/realtime/limits) for the value on your plan.
</Admonition>
### Max payload size in KB
**Type:** Size in KB · **Range:** 1 to your plan's [broadcast payload size](/docs/guides/realtime/limits#limits-by-plan) limit · **Default:** your plan's limit
Determines the maximum payload size in KB that can be sent.
- **Too low**: oversized broadcasts are dropped, and the sender only learns about it if it set `ack_broadcast` to `true`. Broadcast REST requests are rejected with `422`, and an oversized presence `track` closes the channel with `Track message size exceeded`.
- **Too high**: large messages increase memory and bandwidth usage on every subscriber, since each message is delivered to all clients on the channel. Postgres Changes payloads have a [separate limit](/docs/guides/realtime/limits#postgres-changes-payload-limit).