How does realtime work via HTTP with Redis?
how does the real time work via http with redis?
It combines Redis Streams for durability with Redis Pub/Sub for immediate delivery, then exposes events to browsers through HTTP Server-Sent Events (SSE).
Publisher
│ XADD + PUBLISH
▼
Upstash Redis
│ Pub/Sub subscription
▼
Your /api/realtime endpoint
│ HTTP SSE stream
▼
Browser EventSource
###1. Publishing an event
Calling:
await realtime.channel("chat").emit("message.created", data)
does two things in src/server/realtime.ts:
XADDstores the event in a Redis Stream and generates an ID such as1712345678901-0.PUBLISHsends that same event to active subscribers immediately.
Conceptually:
const id = await redis.xadd(channel, "*", {
data,
event,
channel,
})
await redis.publish(channel, {
id,
data,
event,
channel,
})
Redis Pub/Sub provides low-latency notification, while the Stream provides history and recovery if a client disconnects.
###2. Browser connection over HTTP
The React provider creates a normal browser EventSource:
new EventSource(
"/api/realtime?channel=chat&last_ack_chat=1712345678901-0"
)
The API handler returns a streaming HTTP response with:
Content-Type: text/event-stream
Cache-Control: no-cache
Connection: keep-alive
Each Redis message is encoded as an SSE frame:
data: {"id":"1712345678901-0","channel":"chat","event":"message.created","data":{...}}
This is implemented in src/server/handler.ts. There is no application WebSocket connection—the browser keeps an HTTP response open and the server continuously writes SSE messages into it.
###3. Reconnection and missed events
The client remembers the last Redis Stream ID received for each channel. On reconnect it sends that ID as last_ack_<channel>.
The server then executes an exclusive stream range:
redis.xrange(channel, `(${lastAck}`, "+")
That replays events newer than the acknowledged ID before normal live delivery continues.
To avoid a race while history is loading, the server:
- Starts Redis Pub/Sub first.
- Buffers newly arriving live events.
- Loads missing events from the Redis Stream.
- Sends the history.
- Deduplicates buffered events using their stream IDs.
- Flushes the remaining buffer and switches to live delivery.
Thus, Pub/Sub handles “right now”, while Redis Streams handle “what did I miss?”
###4. Connection maintenance
The implementation also:
- Publishes a
pingevery 60 seconds. - Treats a missing ping after 75 seconds as a dead connection.
- Sends a
reconnectsystem event shortly before the serverless function’s maximum duration. - Reopens the SSE request and resumes from the latest acknowledged stream ID.
So “real time via HTTP” here means a long-lived streaming HTTP response, not HTTP polling:
Redis Stream = persistence/replay
Redis Pub/Sub = immediate notification
SSE/EventSource = HTTP delivery to the browser
END OF POST