Comparisons
Pairs that get conflated in real conversations, and in real pull requests. Neither column wins — what decides is the requirement. Each record leads with the confusion, because the confusion is the reason the record exists.
Server-Sent Events vs WebSocket
WebSocket is chosen by default because it sounds like the realtime primitive, and then the application uses it for a feed that never sends anything upward. That choice is not free: you have left HTTP, so you have also left its infrastructure. SSE is a normal HTTP response, which means compression, HTTP caching semantics, standard authentication with cookies or headers, ordinary proxy and load-balancer behaviour, and automatic reconnection with a last-event-id all work without you writing them. WebSocket gives you none of those by default: reconnection, heartbeats, backpressure, message framing, authentication on the upgrade and a re-sync protocol are all yours to implement, and intermediaries handle long-lived upgraded connections less predictably. The other half of the confusion is that either transport solves ordering and duplicates. Neither does. Both need event ids, an idempotent apply step and a resynchronisation path after a gap, because a dropped connection loses events that no reconnect can replay.
One-way updates: notifications, progress, live counters, streamed model output, a feed. The client's side of the conversation is ordinary requests.
Genuine two-way, low-latency traffic where the client sends frequently as well: collaborative editing, multiplayer, live cursors, an interactive terminal.
| Dimension | SSE — a long-lived HTTP response streaming events server-to-client | WebSocket — a bidirectional, framed connection after an HTTP upgrade |
|---|---|---|
| Direction | Server to client only | Both directions |
| Protocol | Plain HTTP response with a streaming body | HTTP upgrade, then its own framed protocol |
| Reconnection | Built in, with last-event-id resumption | You implement it, plus heartbeats |
| Auth | Whatever the origin already uses | Handled on the upgrade; tokens in a URL are a common leak |
| Payload | Text events, one field set per message | Text or binary frames |
| Infrastructure friendliness | High — it is an HTTP response | Lower — proxies, timeouts and LBs vary in how they treat it |
| Server cost | One held connection per subscriber | One held connection per subscriber, plus its own state |
| Still your problem | Ordering, duplicates, gap recovery | Ordering, duplicates, gap recovery — identically |