WebSocket vs SSE¶
1. Decision¶
Choose Server-Sent Events (SSE) for unidirectional, server-to-client real-time streaming (e.g., live news updates, AI LLM token streaming, sports scores, stock price feeds); choose WebSocket for full-duplex, bidirectional real-time communication (e.g., chat applications, multiplayer games, collaborative canvas editing).
2. 30-Second Answer¶
Both WebSocket and SSE provide low-latency real-time data streaming over TCP. Server-Sent Events (SSE) is a lightweight, standardized W3C browser protocol operating strictly unidirectionally from server to client over standard HTTP (text/event-stream). SSE leverages standard HTTP infrastructure (HTTP/2 multiplexing, native browser reconnection via EventSource, HTTP status codes, simple firewall traversal). WebSocket provides full-duplex, bidirectional TCP messaging using custom binary/text frame protocols (ws:// / wss://). Choose SSE when clients only need to receive pushed updates (simpler operational footprint); choose WebSocket when clients must send high-frequency messages back to the server over the same socket connection.
3. Decision Matrix¶
| Option | Best For | Avoid When | Latency | Scalability | Consistency | Operational Complexity |
|---|---|---|---|---|---|---|
| SSE (Server-Sent Events) | LLM token streaming (ChatGPT response), live news feeds, stock tickers, system monitoring alerts | Bidirectional client-server interaction (chat, gaming), binary file streaming | Low (<10ms server push over HTTP/2) | High (Operates over standard HTTP/2 multiplexed connections) | Built-in automatic reconnection & Event ID tracking | Low (Standard HTTP text/event-stream) |
WebSocket (ws:// / wss://) |
Bi-directional interactive chat, collaborative editing (Figma), multiplayer games | Unidirectional server-to-client streaming, simple static news updates | Ultra-Low (<5ms binary frame) | Medium to High (Stateful persistent TCP socket cluster requiring Pub/Sub backplane) | Custom heartbeat & reconnect logic required | Medium to High |
4. Selection Rules¶
| Requirement | Best Choice | Rationale / Example |
|---|---|---|
| LLM Token Response Streaming (ChatGPT UI) | SSE | Server streams text tokens as generated; client makes standard HTTP requests |
| Interactive Real-Time Chat App | WebSocket | Client sends messages and receives incoming peer messages over same socket |
| Native Automatic Browser Reconnection | SSE | Browser EventSource API automatically reconnects and sends Last-Event-ID header |
| HTTP/2 Multiplexing Over Single TCP Connection | SSE | Multiple SSE streams share 1 HTTP/2 TCP connection natively without domain sharding |
| Binary Data Streaming (Audio/Video Chunks) | WebSocket | Native support for ArrayBuffer and Blob binary frames (SSE is UTF-8 text only) |
| Enterprise Corporate Firewall Traversal | SSE | Operates over standard HTTPS Port 443 without triggering WebSocket proxy blocks |
5. Tradeoffs¶
- Unidirectional Simplicity vs Bidirectional Duplex Power
- Gain (SSE): Extremely simple server implementation (
text/event-stream); no custom framing protocol. - Lose (SSE): Client cannot push messages back over the SSE stream (must issue separate HTTP POST calls).
- Standard HTTP/2 Multiplexing vs Custom TCP Socket Management
- Gain (SSE): Runs over standard HTTP/2; bypasses HTTP/1.1 6-connection-per-domain browser limit natively.
- Lose (SSE): Under HTTP/1.1, consuming multiple SSE connections exhausts browser socket pools without HTTP/2.
- Native Auto-Reconnect & Resumption vs Custom Ping/Pong Logic
- Gain (SSE):
EventSourceautomatically retries connection and transmitsLast-Event-IDfor seamless stream resumption. - Lose (WebSocket): Developers must code custom heartbeat ping/pong, reconnect loops, and message buffer queues.
- UTF-8 Text Payload vs Binary Framing Support
- Gain (WebSocket): Efficient binary framing for raw bytes, audio streams, and Protobuf payloads.
- Lose (WebSocket): Requires custom frame parsing libraries.
- Infrastructure & Proxy Compatibility
- Gain (SSE): Leverages standard HTTP load balancers, API Gateways, and corporate proxies without modification.
- Lose (WebSocket): Corporate firewalls or strict proxies may drop
Upgrade: websocketheaders.
6. Interview Counter Questions¶
- How does the
EventSourceAPI in the browser handle automatic reconnection and message recovery viaLast-Event-ID? - What is the HTTP/1.1 6-connection limit bug in SSE and how does HTTP/2 solve it?
- How do you implement SSE streaming in Node.js / Go backend servers (
Content-Type: text/event-stream)? - Why did OpenAI choose SSE over WebSockets for streaming ChatGPT completion responses?
- How does load balancing differ between SSE and WebSockets?
- Can SSE transport binary data (e.g., images/audio)?
- What happens when an Nginx proxy buffers SSE responses, and how do you fix it (
X-Accel-Buffering: no)? - How does cross-origin authorization (CORS & Cookies/Headers) differ between SSE and WebSockets?
- When would you choose Long Polling over SSE?
- How do you scale SSE horizontally across multiple server nodes (Redis Pub/Sub)?
10. Gold Standard Answers¶
- Each SSE event includes an
id: 123tag. If the connection drops,EventSourceautomatically reconnects and sends HTTP headerLast-Event-ID: 123. The server reads this header and replays missed events from that ID offset. - Browsers enforce a max limit of 6 concurrent HTTP/1.1 connections per domain name. Opening 6 SSE tabs blocks all further HTTP requests to that domain. HTTP/2 multiplexes unlimited SSE streams over a single TCP connection, fixing the issue.
- Set headers:
Content-Type: text/event-stream,Cache-Control: no-cache,Connection: keep-alive. Format body:data: {"token": "hello"}\n\n. Flush the response stream immediately after writing each message block. - ChatGPT streaming is strictly unidirectional (server pushing generated LLM tokens to client). SSE utilizes standard HTTP authentication, automatic browser reconnection, zero custom framing, and works natively over HTTP/2 without WebSocket overhead.
- Both require long-lived connections. However, SSE uses standard HTTP, allowing standard L7 HTTP load balancers to route initial GET requests easily. WebSockets require proxies to support HTTP Upgrade headers.
- Not natively. SSE is strictly UTF-8 text. Binary data must be Base64-encoded, which adds a 33% byte size overhead penalty. Use WebSockets for native binary streaming.
- Reverse proxies (Nginx) buffer HTTP responses by default to optimize throughput, holding SSE events in RAM instead of pushing them immediately. Fix by sending header
X-Accel-Buffering: noor settingproxy_buffering off;in Nginx config. - SSE uses standard HTTP, so
EventSourcesupports standard CORS, HTTP authorization headers (viafetchor polyfills), and cookies. WebSockets ignore standard CORS after the initial HTTP Upgrade handshake. - Choose Long Polling only for legacy browsers lacking SSE support, or when infrastructure proxies forcibly terminate long-lived HTTP streaming connections every 30 seconds.
- Just like WebSockets, use a Redis Pub/Sub backplane. When an event occurs, publish to Redis; each SSE server node consumes the message and writes it to matching local client SSE response streams.
8. Common Mistakes¶
- Forgetting to disable response buffering on Nginx (
X-Accel-Buffering: no), causing SSE events to freeze until buffer fills. - Using SSE over HTTP/1.1 across multiple browser tabs, hitting the 6-connection per domain browser limit.
- Encoding large binary media files into Base64 over SSE instead of using WebSockets.
- Using WebSockets for purely unidirectional server-push applications (e.g., live news ticker), adding unnecessary operational complexity.
- Failing to include
\n\ntrailing newlines in SSE message payloads, causing the clientEventSourceto hang waiting for message boundaries.
9. Keywords¶
SSE, Server-Sent Events, WebSocket, EventSource, Last-Event-ID, text/event-stream, HTTP/2 Multiplexing, Unidirectional, Full-Duplex, ChatGPT Token Streaming, X-Accel-Buffering, Base64 Encoding, Redis Pub/Sub.
10. Cheat Sheet¶
- Core Rule: Unidirectional Server-to-Client Stream = SSE; Bidirectional Interactive Communication = WebSocket.
- Protocols: SSE = Standard HTTP/2 (
text/event-stream); WebSocket = Custom TCP protocol (ws://,wss://). - Auto-Reconnect: SSE has native browser auto-reconnect +
Last-Event-IDmessage replay built-in. - Nginx Fix: Always send
X-Accel-Buffering: nofor SSE to prevent Nginx from caching event chunks. - HTTP/2 Requirement: Always run SSE over HTTP/2 to bypass HTTP/1.1's 6-connection per domain browser limit.
- Data Format: SSE = UTF-8 Text only (JSON); WebSocket = Text + Native Binary (ArrayBuffer).