Docs

Database change events

Get told when rows are inserted, updated or deleted: turning change capture on per table, the event format, delivery and ordering, who may listen, and why an event may be missing.

Updated Oct 17, 2026Open in console

With change capture on, every write to a chosen table publishes an event on the channel db.table.<table>. Use it to refresh a list when data changes, without polling.

Turn it on

  1. Realtime › Database change data capture

    Switch it on and pick the tables. Nothing is published for tables you didn't pick.

  2. Allow listeners

    Add a rule that lets the right callers SUBSCRIBE to db.table.<table> (Policy language (SPL)).

  3. Listen

    Subscribe like any channel.

    sovaria.realtime.channel('db.table.orders', {
      onMessage: async (event) => {
        // { event_type: 'row.inserted' | 'row.updated' | 'row.deleted', table, schema, timestamp, event_id, row_count }
        setOrders(await loadMyOrders())   // re-read through your rules
      },
    })

What an event contains

FieldValue
event_typerow.inserted, row.updated or row.deleted
table, schemaThe table that changed (public)
row_countHow many rows the statement changed
timestampWhen it was committed
event_idUnique per event — use it to ignore a duplicate

Events say that rows changed, not their contents. Clients then read what they may see through your access policies and row-level security, so a listener never receives rows it couldn't query itself.

Delivery and ordering

  • Events are written to a durable outbox before the write returns and delivered from there with retries, so a restart delays them rather than losing them.
  • Events for one table arrive in commit order.
  • A retried delivery carries the same event_id; duplicates are dropped by realtime, and your code can ignore any it has already handled.
  • The same events can also call your HTTPS endpoint — database webhooks (Database webhooks).

An event didn't arrive

CheckWhy
Is change capture on for that table?Only picked tables publish.
Did the write happen through Sovaria?Writes over a direct Postgres connection don't go through the API and aren't published.
Did the statement change rows?An update that matched no rows (for example because of row-level security) publishes nothing.
Is the client allowed to subscribe?A refused subscription closes with 4401/4408.
Was the client offline?Catch up with replay (Channels and connections).
Something unclear or missing on this page?Tell us