Live chat
Messages table with realtime inserts and an optional presence channel.
1. Schema
schema.sql
CREATE TABLE messages (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
room TEXT NOT NULL,
author TEXT NOT NULL,
body TEXT NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);Enable the table under dashboard Realtime.
2. Realtime
Pick your framework — selection is remembered across examples.
app/chat/page.tsx
'use client';
import { useEffect, useState } from 'react';
import { createClient } from 'voltbase-js';
const voltbase = createClient(
process.env.NEXT_PUBLIC_VOLTBASE_URL!,
process.env.NEXT_PUBLIC_VOLTBASE_ANON_KEY!,
);
type Message = { id: string; author: string; body: string };
export default function ChatPage() {
const [messages, setMessages] = useState<Message[]>([]);
useEffect(() => {
const unsub = voltbase.realtime.subscribe(
'messages',
(event) => {
if (event.type === 'INSERT') {
setMessages((prev) => [...prev, event.record as Message]);
}
},
{ event: 'INSERT', filter: { room: 'lobby' } },
);
return () => unsub();
}, []);
async function send(body: string) {
await voltbase.from('messages').insert({
room: 'lobby',
author: 'alice',
body,
});
}
return (
<div>
<ul>
{messages.map((m) => (
<li key={m.id}>
<strong>{m.author}</strong>: {m.body}
</li>
))}
</ul>
<button onClick={() => void send('Hello!')}>Send</button>
</div>
);
}3. Presence
lib/presence.ts
const channel = voltbase.realtime.channel('lobby');
channel
.on('presence', { event: 'sync' }, ({ state }) => {
console.log('online', state);
})
.subscribe();
channel.track({ user: 'alice' });Presence is in-memory on a single API instance — fine for demos and single-replica deploys.