Realtime

Live data without a second backend

Postgres change streams, broadcast and presence over one WebSocket, with the same row-level policies deciding what each subscriber sees.

Realtime product screenshot
realtime
volcano cloud config deployrealtime  enabled · broadcast · presence · postgres_changes✓ wss://…/realtime/v1/websocket ready# then, in the browserchannel.onPostgresChanges('INSERT', 'public', 'cards', render)INSERT public.cards  { id: 'c_18f…', title: 'Ship it' }# subscribers only receive rows their policies already allow
Overview

The usual options are polling or a second system

Either you poll every few seconds and send a thousand queries to find out nothing changed, or you stand up a socket tier, a pub/sub broker and a change-capture pipeline, then keep three deployments and one authorization model in agreement.

Volcano puts change streams, broadcast and presence on the database you already have. Subscribe to a table and Volcano installs what it needs to stream that table's changes. Every message is filtered by the same row-level policies that guard a normal query, so the socket needs no permission model of its own.

Transport

One socket, many channels

Channels share the socket, so a screen watching two tables plus a cursor feed and a presence roster still opens one connection. Reconnection, backoff and re-subscribing belong to the SDK.

  • Up to 100 channels per connection on Hobby or 500 on Superagent
  • Change streams, broadcast and presence on the same socket
  • Reconnects and re-subscribes for you
one client, five subscriptions
postgres:public:cards        subscribedpostgres:public:comments     subscribedbroadcast:board-42-cursors   subscribedbroadcast:board-42-typing    subscribedpresence:board-42            subscribed · 7 here✓ sockets open: 1
Setup

Subscribing is the whole setup

Subscribe from the client and Volcano installs the triggers that table needs on the first subscription. There is no replication slot or change-capture pipeline to configure. The table needs row-level security and a primary key, and that is the whole setup.

  • Triggers installed on the first subscription
  • No replication or change-capture pipeline to run
  • Subscribe to one event type or all
volcano.dev/dashboard/realtime
Realtime settings with change streams, broadcast and presence enabled
Authorization

The stream obeys your policies

A change event is delivered to a subscriber only if that subscriber could have selected the row. The rule is the row-level policy you already wrote, so there is no second permission model for the socket.

  • Filtered per subscriber, not per channel
  • Anon key plus the user's token to connect
  • Service keys skip policies, so keep them on a server
one UPDATE, two subscribers
# update cards set title = '…' where id = 'c_18f…'ada   (member of the board)   → UPDATE deliveredcleo  (not a member)          → nothingsame policy as select, applied to the stream
Capabilities

What realtime gives you

Postgres change streams

Subscribe to inserts and updates on any table with row-level security. A server holding the service key also sees deletes.

Broadcast

Send a message to everyone on a channel. Nothing is stored, so it suits cursors and typing indicators.

Presence

Track who is on a channel. The full roster is synced to everyone whenever it changes.

Policy-filtered delivery

Each subscriber receives only the rows their row-level policies would return.

One managed WebSocket

Many channels share one connection, with reconnection handled by the SDK.

Turned on in config

Enable broadcast, presence and change streams in volcano-config.yaml and apply with one command.

Code

Connect, subscribe, publish

TypeScript
import { VolcanoRealtime } from '@volcano.dev/sdk/realtime'; const realtime = new VolcanoRealtime({ apiUrl: process.env.NEXT_PUBLIC_VOLCANO_API_URL!, anonKey: process.env.NEXT_PUBLIC_VOLCANO_ANON_KEY!, accessToken: volcano.accessToken, // With a client and a database, the SDK fetches the changed row for you. volcanoClient: volcano, databaseName: 'app', }); await realtime.connect(); // A Postgres channel is named after the table it streams: schema:table. const cards = realtime.channel('public:cards', { type: 'postgres' }); cards.onPostgresChanges('*', 'public', 'cards', (change) => { // change: { type, schema, table, id, record?, timestamp }. The notification // carries the primary key; record is the fetched row, when the fetch worked. if (change.record) { upsertCard(change.record); } else { refetchCard(change.id); } }); await cards.subscribe();
Use cases

What people make live

presence on board-42
presence_sync   ada · bob · cleopresence_sync   ada · bob · cleo · danapresence_sync   ada · cleo · dana# bob closed his laptop — no heartbeat code involvedroster maintained by Volcano
Platform

Works with the rest of Volcano

Databases and vector
  • The tables you stream

    Change events come from your own Postgres tables, and the read policy decides who receives each one.

Authentication
  • Who is connected

    Subscribers connect with their session token, so presence and filtering use a real user id.

Functions and agents
  • Progress from a job

    A function can broadcast on a channel while it works, so the page updates without polling.

Next.js frontends
  • Live in the browser

    The realtime client runs in a Next.js client component alongside the rest of the SDK.

Frequently asked questions

Read the docs
Do I have to set up change data capture?

No. The first subscription to a table installs the triggers Volcano needs, and its changes stream from then on. There is no replication to configure. The table needs row-level security and a primary key.

Can a subscriber see rows they are not allowed to read?

No. Change events are filtered per subscriber using the same row-level policies that apply to a normal query, so a user receives an event only if they could have selected that row.

What is the difference between broadcast and postgres changes?

Postgres changes follow writes to your tables and are durable because the row is. Broadcast sends a message to whoever is subscribed right now and stores nothing, which suits cursors and typing indicators.

How many channels can one connection carry?

Up to 100 on Hobby or 500 on Superagent. Channels multiplex over the single socket, so a screen watching two tables plus a cursor feed and a presence roster still holds one connection open. Connection and message limits are on the pricing page.

What does a change event contain?

The event type, the table and the row's primary key. Give the realtime client your Volcano client and database name, and the SDK fetches the current row for inserts and updates as well. Previous values are not sent, and a signed-in user's subscription does not receive deletes; a server holding the service key does.

How do I turn realtime on?

Set the realtime block in volcano-config.yaml and run volcano cloud config deploy. There is no realtime CLI and nothing to deploy separately.

Ready to make it live?

Build, deploy, and scale on Volcano's global platform — free to start, with no infrastructure to manage.

Checkout more features