chore(realtime): update protocol documentation (#47528)

## 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?

update protocol documentation for realtime to include new filters for pg
changes, select for pg changes and the new opt in system message
This commit is contained in:
Filipe Cabaço authored and GitHub committed 2026-07-02 15:33:39 +01:00
1 parent 6246f7359f
commit dad7b5f2ee
1 file changed
+38 -14
+38 -14
View File
@@ -214,7 +214,8 @@ This is the initial message required to join a channel. The client sends this me
"replay" : {
"since": integer,
"limit": integer
}
},
"replication_ready": boolean
},
"presence": {
"enabled": boolean,
@@ -225,7 +226,8 @@ This is the initial message required to join a channel. The client sends this me
"event": string,
"schema": string,
"table": string,
"filter": string
"filter": string,
"select": string[]
}
]
"private": boolean
@@ -242,6 +244,7 @@ This is the initial message required to join a channel. The client sends this me
- `replay`: Configuration options for broadcast replay (Optional)
- `since`: Replay messages since a specific timestamp in milliseconds
- `limit`: Limit the number of replayed messages (Optional)
- `replication_ready`: When `true`, the server emits a `system` event once the Postgres replication connection backing this channel is established and ready to stream changes (Optional). See the [system](#system) event for the payload shape.
- `presence`: Configuration options for presence tracking
- `enabled`: Whether presence tracking is enabled for this channel
- `key`: Key to be used for presence tracking, if not specified or empty, a UUID will be generated and used
@@ -249,7 +252,8 @@ This is the initial message required to join a channel. The client sends this me
- `event`: Database change event to listen to, accepts `INSERT`, `UPDATE`, `DELETE`, or `*` to listen to all events.
- `schema`: Schema of the table to listen to, accepts `*` wildcard to listen to all schemas
- `table`: Table of the database to listen to, accepts `*` wildcard to listen to all tables
- `filter`: Filter to be used when pulling changes from database. Read more about filters in the usage docs for [Postgres Changes](/docs/guides/realtime/postgres-changes?queryGroups=language&language=js#filtering-for-specific-changes)
- `filter`: Filter to be used when pulling changes from the database. A filter is a `column=operator.value` expression (for example `id=eq.1` or `title=like.%foo%`). Multiple conditions can be combined with commas and are applied as an `AND` (for example `id=gt.0,id=lt.100`). Any operator can be negated with the `not.` prefix (for example `status=not.in.(draft,archived)`). Reserved characters (`,`, `(`, `)`) inside a value must be double-quoted PostgREST-style (for example `name=eq."a,b"`). See the [Postgres Changes subscription errors](#postgres-changes-subscription-errors) for the full list of supported operators, and the usage docs for [Postgres Changes](/docs/guides/realtime/postgres-changes?queryGroups=language&language=js#filtering-for-specific-changes).
- `select`: Optional array of column names to restrict the change payload to a subset of columns instead of receiving the full row. Reduces payload size and the data transferred per event. The listed columns must be selectable by the subscribing role. Not supported for wildcard (`*`) schema or table subscriptions — an explicit `schema` and `table` are required.
- `access_token`: Optional access token for authentication, if not provided, the server will use the API key.
Example on protocol version `2.0.0`:
@@ -564,7 +568,7 @@ The server sends system messages to inform clients about the status of their Rea
- `message`: A human-readable message describing the status of the subscription.
- `status`: The status of the subscription, can be `ok`, `error`, or `timeout`.
- `extension`: The extension that sent the message.
- `extension`: The extension that sent the message. `postgres_changes` for Postgres Changes subscription status, or `system` for connection-level messages such as the replication-ready notification.
- `channel`: The channel to which the message belongs, such as `realtime:room1`.
Example on protocol version `2.0.0`:
@@ -584,6 +588,23 @@ Example on protocol version `2.0.0`:
]
```
When a channel is joined with `config.broadcast.replication_ready` set to `true`, the server sends a `system` message with `extension: "system"` once the Postgres replication connection backing the channel is ready to stream changes. `status` is `"ok"` with `message: "Replication connection established"` on success, or `"error"` if the connection is not established in time (which also closes the channel — see [Channel-level system errors](#channel-level-system-errors)).
```json
[
"14",
null,
"realtime:chat-room",
"system",
{
"message": "Replication connection established",
"status": "ok",
"extension": "system",
"channel": "main"
}
]
```
{/* supa-mdx-lint-disable-next-line Rule001HeadingCase */}
#### broadcast (text frame)
@@ -715,6 +736,8 @@ The server sends this message when a database change occurs in a subscribed sche
- `old_record`: An object representing the old values before the change, with keys as column names and values as their corresponding values.
- `errors`: Any errors that occurred during the change, if applicable.
When the subscription was joined with a `select` array (see [phx_join](#phx_join)), `columns`, `record`, and `old_record` are restricted to the selected columns instead of the full row.
```json
[
null,
@@ -926,15 +949,16 @@ One exception: the `UnknownErrorOnChannel` code arrives as the bare human-readab
`extension: "system"`, `status: "error"`. Match on the `message` field content — there is no machine-readable code field. Every channel-level system error is immediately followed by `phx_close`; the channel is closed. Client libraries should expose a way for users to subscribe to `system` events since there is no automatic handling.
| Message contains | Cause | Recovery |
| ------------------------------------------------- | -------------------------- | ----------------------------- |
| `Too many messages per second` | Broadcast/event rate limit | Throttle sends before rejoin |
| `Too many presence messages per second` | Tenant presence rate limit | Reduce presence frequency |
| `Client presence rate limit exceeded` | Per-client presence window | Longer cooldown before rejoin |
| `Track message size exceeded` | Presence payload too large | Shrink payload |
| `Token has expired` | JWT expired mid-session | Refresh token, rejoin |
| `Fields \`role\` and \`exp\` are required in JWT` | Claims missing | Fix token issuance |
| `Server requested disconnect` | Operational disconnect | Reconnect after delay |
| Message contains | Cause | Recovery |
| ---------------------------------------------------- | -------------------------------------------------------------------------------------------------- | ----------------------------- |
| `Too many messages per second` | Broadcast/event rate limit | Throttle sends before rejoin |
| `Too many presence messages per second` | Tenant presence rate limit | Reduce presence frequency |
| `Client presence rate limit exceeded` | Per-client presence window | Longer cooldown before rejoin |
| `Track message size exceeded` | Presence payload too large | Shrink payload |
| `Token has expired` | JWT expired mid-session | Refresh token, rejoin |
| `Fields \`role\` and \`exp\` are required in JWT` | Claims missing | Fix token issuance |
| `Server requested disconnect` | Operational disconnect | Reconnect after delay |
| `Replication connection was not established in time` | Replication connection not ready before the deadline (only when `replication_ready` was requested) | Retry with backoff |
### Postgres Changes subscription errors
@@ -948,7 +972,7 @@ One exception: the `UnknownErrorOnChannel` code arrives as the bare human-readab
| Database error during subscription | Yes, every 5–10 s | Surface as degraded state |
| `"Too many database timeouts"` | No | Reduce subscription load; retry later |
Supported filter operators: `eq`, `neq`, `lt`, `lte`, `gt`, `gte`, `in`.
Supported filter operators: `eq`, `neq`, `lt`, `lte`, `gt`, `gte`, `in`, `like`, `ilike`, `is`, `match`, `imatch`, `isdistinct`. Any operator can be negated with the `not.` prefix (for example `id=not.eq.5`). Multiple conditions are combined with commas and applied as an `AND` (for example `col1=eq.val,col2=gt.5`).
The `ids` array on incoming `postgres_changes` payloads must match the subscription IDs returned in the `phx_join` reply. A mismatch means inconsistent server/client state — tear down and rejoin.