Skip to Content
BuildRealtime

Realtime

Subscribe to a table and get a callback the moment a row changes — no polling. Realtime is the same database you already query, pushed to you live: it’s backed by Postgres LISTEN/NOTIFY, streamed out through the Data Gateway over SSE/WebSocket.

The most important property: the live feed is filtered by the same .policy predicate as select. Subscribers never receive a row they couldn’t have read in a query — so the anon key is as safe on a subscription as it is on a fetch.

Subscribe to a table

Chain .on(event, callback) off zxcv.from('table'), then .subscribe(). Each matching change invokes your callback with the row:

const channel = zxcv .from('messages') .on('insert', (row) => { console.log('new message', row) }) .subscribe()

You’ll only be handed rows that pass the messages read rule for the current user — the gateway applies authorization to the stream, not just to one-off queries.

Events

Listen for 'insert', 'update', or 'delete'. Register more than one by chaining .on(...) before .subscribe():

const channel = zxcv .from('messages') .on('insert', (row) => addMessage(row)) .on('update', (row) => updateMessage(row)) .on('delete', (row) => removeMessage(row)) .subscribe()

Unsubscribing

subscribe() returns a channel. Tear it down when you’re done to close the connection and stop receiving events:

channel.unsubscribe()

Always unsubscribe when the consumer goes away. In a UI, do it when the component unmounts — a subscription that outlives its view leaks a connection.

Use it in the client

Realtime shines in client-side code, where the anon key already lives and the UI needs to update live. Set up the channel when the view mounts, tear it down when it leaves:

components/Messages.tsx
'use client' import { useEffect, useState } from 'react' import { zxcv } from '@/lib/zxcv' export function Messages() { const [messages, setMessages] = useState<Message[]>([]) useEffect(() => { // load what already exists... zxcv.from('messages').select('*').order('id').then(({ data }) => { if (data) setMessages(data) }) // ...then stream new rows as they arrive const channel = zxcv .from('messages') .on('insert', (row) => setMessages((prev) => [...prev, row])) .subscribe() return () => channel.unsubscribe() }, []) return ( <ul> {messages.map((m) => ( <li key={m.id}>{m.body}</li> ))} </ul> ) }

Doing this in Next.js? The subscription must run in a Client Component — mark the file 'use client', as above. See the Next.js quickstart for the client/server split.

Next steps

  • Database — the tables you subscribe to and their rules
  • SDK reference — the full realtime and query API