Back to Blog
SSEWebSocketsreal-timeNode.jsarchitecture

SSE vs WebSockets for real-time terminal output

February 10, 20266 min read

When I needed to stream live process output to the browser I chose Server-Sent Events over WebSockets. Here is the reasoning, the trade-offs, and when each one wins.

The default answer is wrong

When developers need to push data from server to browser in real time, the instinct is to reach for WebSockets. They're the "real-time" technology. But WebSockets are a bidirectional full-duplex protocol — and sometimes you simply don't need full duplex. Choosing the right tool starts with asking: who needs to talk, and in which direction?

What SSE actually is

Server-Sent Events (SSE) is an HTTP-based protocol where the server keeps a connection open and pushes newline-delimited text frames to the browser. The browser side is the native EventSource API. That's it. No upgrade handshake, no binary framing, no persistent socket state. Just a long-lived GET request with Content-Type: text/event-stream.

When SSE wins

SSE is the right choice when: - The flow is server → client only (live logs, notifications, progress bars, streaming LLM output) - You want automatic reconnect for free (EventSource reconnects on drop without any code) - You're behind a standard HTTP reverse proxy (Nginx, Caddy, AWS ALB — no special WebSocket config needed) - You want HTTP/2 multiplexing — SSE rides on the existing H2 connection, WebSockets require a separate socket For RootResume, streaming process stdout to the browser is a perfect one-way flow. SSE was the obvious choice.

When WebSockets win

WebSockets win when: - You need true bidirectional low-latency communication (multiplayer games, collaborative editing, chat with typing indicators) - You're sending binary data at high frequency (audio/video, binary game state) - You need sub-100ms round-trip where the HTTP overhead of SSE frames actually matters For a chat app, a multiplayer canvas, or a real-time collaborative IDE — use WebSockets.

The practical difference in Node.js

With SSE, the server side is a plain Express response handler: js res.setHeader('Content-Type', 'text/event-stream'); res.setHeader('Cache-Control', 'no-cache'); process.stdout.on('data', chunk => { res.write(`data: ${encode(chunk)}\n\n`); }); With WebSockets you need an upgrade handler, a ws library, and to manage socket lifecycle separately from your HTTP server. More surface area, more failure modes.

Written by Luna Lancuba

← More articles