You are designing a one-way live feed of order-status updates for a web app, and the team's instinct is to reach for WebSockets. How would you decide between server-sent events, WebSockets, and periodic polling?
answer
- direction, rate, payload, concurrency
- one-way traffic does not need duplex
- SSE is ordinary HTTP, so auth is inherited
- reconnection free versus built by hand
- polling is the baseline to beat
basics
~20 sMatch the transport to the traffic shape. A one-way feed suits server-sent events, which ride ordinary HTTP and reconnect themselves; WebSockets earn their extra machinery only with real client-to-server chat; polling wins when updates are rare and latency tolerance is loose.
solid answer
~50 sI start from the traffic shape, not the technology. This feed is one-way, low-volume and textual, which is exactly what `EventSource` is for: it is a plain HTTP GET, so it inherits the auth, CORS rules, load balancing and observability the rest of the API already has, and the browser supplies reconnection for free. WebSockets buy full-duplex and binary framing — real value when the client is also sending continuously, and unnecessary cost otherwise, because you then own reconnection, heartbeats, a separate auth story, and infrastructure that may treat the connection differently. Polling stays on the table and is often right: if updates are rare or a delay of some seconds is acceptable, a periodic request has no held connection and no reconnect logic at all. Then I check the constraints that actually bite: `EventSource` cannot send custom headers, HTTP/1.1 caps concurrent connections per origin, and buffering intermediaries can delay events. Finally I put the choice behind a small interface so it stays reversible.
go deeper
Know the basic shapes: server-sent events are one-way over ordinary HTTP with reconnection built in, WebSockets are two-way, and polling is a repeated request.
Explain the concrete trade — SSE inherits existing HTTP auth, CORS and infrastructure and gives you reconnection for free, while WebSockets add duplex and binary at the cost of reconnect, heartbeat and auth work you now own.
Bring the constraints that decide it in production: browser connection limits per origin, server capacity per held connection, buffering intermediaries, and the fact that EventSource cannot send an Authorization header.
Frame it as a reversible decision with a measurement plan — name the traffic properties that drive the choice, the capacity ceiling for each option, and the interface that keeps the transport swappable when evidence changes.
## Start from the traffic, not the technology The question "SSE or WebSockets?" is usually asked backwards. Four properties of the traffic decide it, and they are all knowable before any code exists: - **Direction.** Does the client send continuously, or only occasionally? Order status updates flow one way; the occasional "cancel this order" is a normal request. - **Rate and latency budget.** Ten updates a minute with a two-second tolerance is a completely different problem from a hundred a second with a fifty-millisecond budget. - **Payload.** Text, or binary frames where encoding overhead matters? - **Concurrency.** How many clients hold a connection at once, and what does each cost your server? Only after those are written down does the transport follow. ## What each option actually costs **Polling.** Least machinery: an ordinary request on a timer. No held connection, no reconnect logic, no special infrastructure, trivially debuggable and cacheable. It costs request overhead per client per interval and imposes a latency floor equal to the interval. Polling is the right answer far more often than engineers like to admit, and it is the correct baseline to argue *against* rather than skipping straight past it. **Server-sent events.** The browser opens one long-lived GET and the server writes messages as they happen. The strategic property is that **it is just HTTP**. Your existing cookie or session auth applies, CORS behaves as it does everywhere else, proxies and load balancers route it as a normal request, and your access logs and tracing see it. The client API is small, and the reconnection loop — the piece teams most often get wrong by hand — is supplied by the browser. The costs: one-way only, text only, no custom request headers from `EventSource`, and a connection held open per client. **WebSockets.** Full duplex over a persistent connection, with binary support and lower per-message overhead. That is genuinely necessary for collaborative editing, multiplayer interaction, or a chat-shaped workload. The price is a separate protocol with its own operational surface: you build reconnection and liveness checks yourself, you design an authentication scheme that fits a long-lived connection rather than a per-request one, and your edge, load balancers and observability tooling need to handle it deliberately. None of that is hard; all of it is work you do not do if the feed is one-way. ## The constraints that actually bite Four things turn a clean decision into a production incident, and a good answer names them. **Concurrent connections in the browser.** Over HTTP/1.1 a browser allows only about six connections per origin, and a stream never returns one. A user with several tabs open can exhaust the budget and stall unrelated requests to that origin. Over HTTP/2 or HTTP/3 the limit becomes concurrent streams on one connection — roughly a hundred — which removes the pressure. If you cannot serve HTTP/2 on that origin, that argues for polling or for sharing a single stream across tabs. **Concurrent connections on the server.** Every held connection is memory, a file descriptor, and usually a per-client subscription in whatever broker feeds it. A hundred thousand concurrent users on a one-message-per-minute feed is a capacity design problem regardless of which transport you choose; polling converts it into a request-rate problem instead, which some stacks absorb far more comfortably. **Intermediaries.** Anything between server and browser that buffers a response before forwarding it will hold your events until its buffer fills or the response ends — which, for a stream that never ends, means arbitrary delay. This has to be verified through the real production path, not on localhost, and it applies to any streaming approach. **Header-based auth.** The browser's `EventSource` cannot attach an `Authorization` header. If your platform is uniformly bearer-token based, either the stream endpoint accepts a cookie or a short-lived token in the URL, or you read the stream with a request you can configure — at which point you have given up the free reconnection that made `EventSource` attractive. ## The decision, stated plainly For a one-way order feed I would choose server-sent events when the updates are frequent enough that polling's latency floor is unacceptable, when the endpoint can be served over HTTP/2, and when cookie auth is available or can be. I would choose polling when updates are rare, when connection counts are large relative to what the server can hold, or when the infrastructure path cannot be trusted to stream. I would choose WebSockets when — and only when — the client genuinely needs to push a continuous stream too, and I would accept the reconnection, heartbeat and auth work as the price of that. ## Keep it reversible Whichever way it goes, the application should see a subscribe-and-unsubscribe interface, not the transport. That makes the choice a one-file change, lets you start with polling and upgrade only if measurement demands it, and gives you a fallback when a customer's corporate proxy turns out to break streaming. Deciding well matters less than making the decision cheap to revisit — and the measurement that would trigger revisiting (delivery latency, reconnect rate, concurrent connections held) should be instrumented on day one.
- The team argues WebSockets are 'more scalable'. How do you answer?Scalability here is about held connections, and both transports hold one per client — the framing overhead difference is negligible for a low-rate text feed. The real capacity questions are how many concurrent connections your servers and broker can carry and what each costs; WebSockets do not improve that. Polling is the option that changes the shape of the problem, trading held connections for request rate.
- What would make you reject server-sent events after choosing them on paper?An infrastructure path that buffers responses, so events arrive in bursts or minutes late; an origin you cannot serve over HTTP/2, leaving the browser's six-connection budget exposed to multi-tab users; or an auth model that is strictly header-based with no cookie or short-lived URL token option. Each is verifiable before commitment, through the real production path rather than on localhost.
- How do you keep this decision cheap to change later?Put a subscribe/unsubscribe interface between the app and the transport, so the application never sees an EventSource or a socket directly. Then instrument the things that would trigger a change — delivery latency, reconnect rate, concurrent connections held, messages per client — from day one. Starting with polling behind that interface and upgrading on evidence is usually cheaper than starting with the sophisticated option.
saying these in an interview costs you the question
- Choosing WebSockets by default for any real-time feature
- Claiming SSE cannot scale because it is 'just HTTP'
- Ignoring polling as a legitimate option
- Forgetting that WebSocket reconnection and heartbeats are your job
- Assuming intermediaries will forward a stream without buffering