Documentation
Realtime 2.0
WebSocket and SSE realtime updates via Postgres LISTEN/NOTIFY
Realtime 2.0
🔌 Bidirectional WebSocket Communication
Implemented in stackhouse/src/realtime/mod.rs, mounted at /v1/realtime (create_realtime_router: WS upgrade at /v1/realtime, status at /v1/realtime/status). Change detection uses PostgreSQL LISTEN/NOTIFY fanned out over tokio::sync::broadcast channels per table — not Postgres logical replication.
WebSocket vs SSE
WebSocket (New)
✅ Bidirectional (client can send messages) ✅ Lower latency than polling ✅ Binary support ✅ Multiplexing (multiple subscriptions)
SSE (Legacy)
✅ Unidirectional (server to client only) ✅ Browser support (all browsers) ✅ Simpler implementation ⚠️ Higher latency
Protocol
Client → server messages (SubscriptionMessage in realtime/mod.rs):
{ "type": "subscribe", "table": "users", "event": "INSERT" }
{ "type": "subscribe", "table": "users", "event": "*" }
{ "type": "unsubscribe", "table": "users" }event accepts "INSERT", "UPDATE", "DELETE", or "*" (all events); a filter field is also accepted on subscribe for row-level filtering.
Server → client push events (RealtimeEvent):
{ "type": "INSERT", "table": "users", "record": {...}, "timestamp": "..." }
{ "type": "UPDATE", "table": "users", "record": {...}, "old_record": {...}, "timestamp": "..." }
{ "type": "DELETE", "table": "users", "old_record": {...}, "timestamp": "..." }JavaScript Example
// Connect
const ws = new WebSocket('ws://localhost:3000/v1/realtime');
ws.onopen = () => {
console.log('Connected');
// Subscribe to a table
ws.send(JSON.stringify({
type: 'subscribe',
table: 'users',
event: '*'
}));
};
ws.onmessage = (event) => {
const msg = JSON.parse(event.data);
console.log('Update:', msg.type, msg.table, msg.record ?? msg.old_record);
};
// Unsubscribe
ws.send(JSON.stringify({
type: 'unsubscribe',
table: 'users'
}));Python Example
import asyncio
import websockets
import json
async def stackhouse_client():
uri = "ws://localhost:3000/v1/realtime"
async with websockets.connect(uri) as ws:
# Subscribe
await ws.send(json.dumps({
"type": "subscribe",
"table": "users",
"event": "*"
}))
# Listen
while True:
msg = await ws.recv()
data = json.loads(msg)
print(f"Update: {data}")
asyncio.run(stackhouse_client())Next: API Reference 🚀