Aller au contenu
Bastide Connexion Créer un compte
Press / to search

Realtime

FrançaisMarkdownv0.3.0

Realtime pushes messages to your connected users without them polling the server: client-to-client broadcast, presence (who is online), and broadcasting a table's changes. It speaks the supabase-js protocol. This page explains how to enable it, how to use it, what is not served, and the quotas of each tier.

What is served

  • Broadcast: a client sends a message on a channel, the other subscribers receive it. It goes over the WebSocket, or over REST (POST /realtime/v1/api/broadcast), the supabase-js fallback.
  • Presence: each client announces its state, and everyone sees who is there.
  • Broadcast from the database: a function sets a trigger on a table, and every insert, update or delete is broadcast on a channel.
  • Private channels, judged by the policies you write on realtime.messages.

The WebSocket is wss://<identifier>.donnees.bastide.app/realtime/v1/websocket, protocols 1.0.0 and 2.0.0 (see Database for the address).

Attention. Listening to database changes through postgres_changes is not served: such a subscription is refused when joining the channel (status error), and the refusal names broadcast from the database (LIM-08). No logical replication is exposed.

Enabling realtime

Realtime is off by default. While it is off, /realtime/v1 answers 403, code temps_reel_inactif.

  • Console: open Données (Data), section « Temps réel » (realtime), then « Activer le temps réel » (enable realtime). The card shows your tier's quotas.
  • Agent: backend_realtime_configure with active: true (rank maintainer, scope db:write).
  • Command line: bastide backend realtime configure --project-id <project> --active true.
  • API: PUT /v1/projects/{projectId}/backend/realtime.
{
  "projectId": "prj_01JQ8ZK4M7NP2RSTVWXYZ34567",
  "active": true,
  "idempotencyKey": "temps-reel-2026-10-28"
}

Enabling and disabling take effect within 30 seconds. Disabling closes the project's open connections, without touching other projects. The state and quotas can be read back with backend_read (the tempsReel field).

Broadcasting and tracking presence

const channel = supabase.channel("room-42");

channel
  .on("broadcast", { event: "cursor" }, ({ payload }) => draw(payload))
  .on("presence", { event: "sync" }, () => console.log(channel.presenceState()))
  .subscribe(async (status) => {
    if (status === "SUBSCRIBED") await channel.track({ name: "Lea" });
  });

await channel.send({ type: "broadcast", event: "cursor", payload: { x: 10, y: 20 } });

A channel topic starts with realtime: in the protocol; supabase-js adds it for you.

Broadcasting a table's changes

Instead of postgres_changes, set the trigger once, in a migration or in the SQL editor:

select realtime.diffuser_les_changements('public.messages');

The public:messages channel then receives every insert, update and delete on the table, as broadcast. Messages coming from the database count against the project's messages-per-second quota; beyond it, they are dropped.

Private channels

A private channel admits only the clients your policies admit. Write them on the realtime.messages table, with realtime.topic() (the channel's topic) and auth.uid():

  • the SELECT policy decides who can join and read the channel;
  • the INSERT policy decides who can send to it.

The platform tests the policy inside a transaction that is always rolled back, under the caller's role: PostgreSQL judges it, exactly as you wrote it. See Data security.

Quotas by tier

TierMessages per secondConcurrent connections
Discovery100200
Standard5002,000
Pro2,50010,000
Sovereignnegotiated, no cap enforcednegotiated, no cap enforced

On every tier: 100 channels per connection, a payload of at most 3,000 KB per message, and 5 presence calls per client per 30-second window.

  • Connections: the slot is reserved before the handshake. Beyond the quota, the WebSocket gets 429, code connexions_simultanees_depassees, without any connection being opened.
  • Messages: the quota is counted per full second, for the whole project (broadcasts, presence and database messages). Beyond it, the send gets an error naming the quota; over REST, 429.
  • Channels: beyond 100 on one connection, joining is refused; leave one, or open another connection.

Note. Realtime holds, per platform instance, one session-mode connection to your database while a client is connected. It counts against your tier's server connection ceiling (three on Discovery; see Database).

Common errors

  • **403 temps_reel_inactif**: enable realtime for the project.
  • Subscription refused, with a reason pointing to broadcast from the database: you asked for postgres_changes; use realtime.diffuser_les_changements.
  • **429 connexions_simultanees_depassees**: close unused connections, or change tier.
  • « jeton d'accès refusé » (access token refused) when joining: the session token expired; reconnect the client.
  • Nothing arrives on a private channel: the SELECT policy on realtime.messages does not admit this user.

See also

Report a mistake on this page