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:
'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