Server-Sent Events are still useful because many product streams are one-way. Build status, log tails, notification badges, queue progress, and agent activity usually flow from server to browser. For those cases, SSE gives you streaming over ordinary HTTP with automatic reconnect and a tiny browser API.
The minimum endpoint
An SSE response is just text with a specific content type. Each message ends with a blank line. The browser exposes the stream throughEventSource.
export async function GET() {
const stream = new ReadableStream({
start(controller) {
controller.enqueue("event: ready\n");
controller.enqueue('data: {"ok":true}\n\n');
},
});
return new Response(stream, {
headers: {
"Content-Type": "text/event-stream",
"Cache-Control": "no-cache",
"Connection": "keep-alive",
},
});
}Use named events and ids
Named events keep client handlers tidy. Event ids let the browser sendLast-Event-ID on reconnect, which gives the server a way to resume from a known point or decide that the client needs a fresh snapshot.
id: 1842
event: job-status
data: {"jobId":"build-7","status":"passed"}If exact replay matters, persist events in a short retention buffer. If it does not, send a full state snapshot after reconnect and continue with incremental updates.
Authentication tradeoffs
Native EventSource does not let you set arbitrary headers. Cookie-based auth is the simplest fit. If your app depends on bearer tokens in headers, you can use a fetch-based SSE parser, a short-lived signed URL, or switch to WebSockets where custom connection setup is already part of the model.
Scale with one stream per screen
The biggest SSE mistake is opening one stream per entity. Prefer one stream per screen or feature area, then multiplex inside the payload. This protects HTTP/1.1 connection budgets and makes server cleanup easier.
When WebSockets are better
Use WebSockets when the browser needs frequent low-latency writes to the server, when you need a custom bidirectional protocol, or when the infrastructure already standardizes on a socket gateway. Use SSE when the server mostly talks and the browser mostly listens.
The best 2026 SSE architecture is intentionally modest: one durable stream, explicit events, reconnect semantics, and a fallback snapshot path.