Skip to content
BunBase BunBase BunBase Docs Alpha v0.1.0

Realtime

client.realtime manages a WebSocket connection with auto-reconnect.

const unsub = client.realtime.subscribe<Post>("collection:posts", (event) => {
console.log(event.event); // "create" | "update" | "delete"
console.log(event.collection); // "posts"
console.log(event.record); // Post & BunBaseRecord
});
// Unsubscribe
unsub();

The WebSocket connects lazily on the first subscribe call. Authentication is sent automatically using the current access token.

const unsub = client.realtime.subscribe<Post>(
posts.recordChannel("01JKX..."),
(event) => {
if (event.event === "update") setPost(event.record);
if (event.event === "delete") router.push("/");
},
);
import { useEffect, useState } from "react";
import type { Post } from "./types";
import { client } from "@/lib/bunbase";
function PostList() {
const [items, setItems] = useState<Post[]>([]);
useEffect(() => {
// Load initial data
client.collection<Post>("posts")
.list({ sort: "-_created_at", limit: 50 })
.then((r) => setItems(r.items));
// Subscribe to live updates
const unsub = client.realtime.subscribe<Post>("collection:posts", (event) => {
if (event.event === "create") {
setItems((prev) => [event.record, ...prev]);
}
if (event.event === "update") {
setItems((prev) =>
prev.map((p) => (p._id === event.record._id ? event.record : p))
);
}
if (event.event === "delete") {
setItems((prev) => prev.filter((p) => p._id !== event.record._id));
}
});
return unsub; // cleanup on unmount
}, []);
return (
<ul>
{items.map((p) => (
<li key={p._id}>{p.title}</li>
))}
</ul>
);
}
  • Connects lazily on first subscribe
  • Sends auth message with current token automatically
  • On unexpected disconnect: reconnects with exponential backoff (500ms → 30s max)
  • On reconnect: re-subscribes all active channels automatically
const off = client.realtime.onConnect(() => {
console.log("Connected!");
off();
});

Fires immediately if already connected.

try {
await client.realtime.ping(3000); // 3s timeout
console.log("Connection is alive");
} catch {
console.log("Connection dead or timed out");
}

Useful for detecting stale connections on mobile (e.g. after backgrounding the app).

const channels = await client.realtime.getSubscriptions();
// ["collection:posts", "record:posts:01JKX..."]
client.realtime.disconnect();
// Closes WebSocket cleanly. No reconnect will be attempted.

Query which users are currently subscribed to a channel on this server worker:

const users = await client.realtime.presence("collection:posts");
console.log(users); // ["01JKX...", "01JKY..."]

Returns user IDs of authenticated connections subscribed to the channel. In multi-worker deployments, presence reflects only connections on the worker that receives the query.

You can also set a global callback:

client.realtime.onPresence = (channel, users) => {
console.log(`${users.length} users on ${channel}`);
};

When the server revokes or invalidates your session, it pushes an auth event over the WebSocket:

EventMeaning
session_revokedThis specific session was revoked by an admin
sessions_purgedAll sessions for this user were revoked
account_deletedThe user account was deleted
password_changedThe user’s password was changed by an admin

For session_revoked, sessions_purged, and account_deleted: the SDK automatically clears tokens and calls disconnect(). For password_changed: tokens are cleared but the connection stays open.

The correct way to react is client.auth.onAuthChange — it fires for all auth state changes: login, logout, silent refresh, and server-pushed revocation events over WebSocket.

client.auth.onAuthChange((session) => {
if (!session) {
// Fires immediately when the server pushes a revocation event.
router.push("/login");
}
});

When a realtime connection is active, onAuthChange(null) fires instantly. This replaces the need for startSessionWatch() polling — that remains useful only in non-WebSocket environments (server-side rendering, API-only clients).

Method / PropertyDescription
subscribe(channel, callback)Subscribe and return unsubscribe fn
onConnect(callback)Fire once when connected
ping(timeoutMs?)Send ping, resolve on pong
getSubscriptions(timeoutMs?)List active server-side subscriptions
presence(channel, timeoutMs?)Query users subscribed to a channel
onPresenceCallback for presence responses
disconnect()Close connection cleanly