API design

WebSockets vs server-sent events

API designReal-time systemsDecision guide

Short answer

Choose server-sent events when the server streams updates to a browser and the client can send commands over ordinary HTTP. Choose WebSockets when both directions need low-latency messages or a single connection carries interactive state; do not pay WebSocket complexity for a one-way feed.

Written and reviewed by Sahil Srivastav

What each one actually is

WebSockets upgrade a connection into a bidirectional message channel. The server and client can send independently, but the application must define framing, heartbeats, reconnects, authentication expiry, and backpressure.

Server-sent events use a long-lived HTTP response with `text/event-stream`. Browsers reconnect natively and receive named, ordered server events; client-to-server actions remain ordinary HTTP requests.

Neither is a durable queue. Persist events or a cursor if a disconnected client must catch up, and treat reconnect as a normal state transition.

Side by side

 WebSocketsServer-sent events
DirectionBidirectionalServer to client; commands use HTTP
Browser APIWebSocketEventSource with automatic reconnect
Protocol overheadLow after upgradeSimple HTTP streaming
IntermediariesUpgrade and idle timeout support requiredWorks through more HTTP infrastructure
Reconnect stateApplication-definedLast-Event-ID and retry support
BackpressureMust be designed in both directionsServer stream needs buffering and disconnect policy
Fan-outConnection broker or gateway often neededStill needs connection capacity and event routing
Best fitChat, collaboration, interactive gamesNotifications, dashboards, progress feeds

Choose WebSockets when

  • The client must send frequent messages without separate HTTP requests
  • A chat, collaboration, or control loop needs bidirectional low latency
  • The protocol can define heartbeats, flow control, and reconnect semantics
  • WebSocket-aware gateways and capacity planning are available

Choose Server-sent events when

  • Updates flow primarily from server to browser
  • Browser reconnect and event IDs reduce client code
  • Existing HTTP proxies and ingress should handle the stream
  • Commands can use ordinary authenticated HTTP endpoints

The trade-off in detail

WebSockets remove HTTP request overhead but create long-lived connection ownership. Track connection counts, heartbeat timeouts, deploy draining, and which node owns each subscription.

SSE is easy to consume but is still a stream of live connections. Set per-client buffer limits and disconnect slow consumers; otherwise one tab can retain unbounded memory.

A reconnect can miss events in either model. Include a sequence or cursor and provide a catch-up endpoint when the UI cannot tolerate gaps.

Things that are commonly said and are wrong

  • “SSE is polling.” It is a long-lived HTTP stream, not repeated requests, though reconnects and keepalives still consume resources.
  • “WebSockets guarantee message delivery.” Messages can be lost on disconnect unless the application persists and replays them.
  • “SSE cannot be authenticated.” Cookies, bearer headers through a fetch-based client, or a short-lived stream token can authenticate it; choose the browser API accordingly.

Decide it in a real repository

Choosing correctly on a whiteboard and enforcing the choice in code are different skills. Gronex ships broken backend repositories whose tests assert the invariant, not the happy path.

FAQ

Which should a dashboard use?

SSE is usually the better fit for server-to-browser metrics or job progress. Add a catch-up cursor and disconnect slow clients rather than letting buffers grow.

Can SSE send client messages?

The EventSource API is one-way. Send commands with ordinary POST or fetch requests, or choose WebSockets when a continuous bidirectional channel is central.

How do I deploy WebSocket servers?

Drain new connections, allow existing ones to close or migrate, and ensure subscription state can be rebuilt. A load balancer timeout or rolling restart otherwise looks like random disconnects.

Other decisions engineers weigh