Skip to main content

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 🚀