Development··2 min read

WebSocket vs SSE: My Realtime Misadventure

Building realtime notifications, I went down the WebSocket rabbit hole before realizing SSE was the answer all along.

We needed realtime notifications

An internal dashboard needed realtime notification support. When an order comes in, it should appear on the relevant person's screen immediately. "WebSocket should handle this, right?" -- so I installed socket.io right away.

That's where the trouble started.

WebSocket: more annoying than expected

Getting socket.io connected was quick. Basic connection in 10 minutes, sending and receiving events is straightforward. But when it came time to go to production, issues poured in.

First, the load balancer. Unlike HTTP, WebSocket requires persistent connections, which meant configuring sticky sessions on the load balancer. Spent 2 hours fiddling with AWS ALB settings.

Second, reconnection logic. When the network drops and reconnects, how do you handle missed messages? socket.io does auto-reconnection, but catching up on missed events is on you.

(At this point, the scope was already ballooning.)

Wait -- do we even need bidirectional communication?

When I thought about it honestly, our feature was purely server-to-client notifications. The client never needed to send realtime data back to the server. This was notifications, not chat.

That's when I belatedly realized SSE (Server-Sent Events) was a better fit. SSE is HTTP-based, so no load balancer fuss. The browser handles reconnection automatically. The EventSource API is simpler than WebSocket.

Switched to SSE

Ripped out all the socket.io code and reimplemented with SSE. Server-side code was cut in half. On the frontend, new EventSource('/api/notifications') -- one line and you're connected.

After 3 weeks in production, connections barely dropped, and notification latency averaged 340ms, which was perfectly fine. Those 3 days of WebSocket wrangling felt pointless.

SSE does have limitations though

There's a limit on concurrent connections per browser. On HTTP/1.1, it's 6 per domain. Open multiple tabs and you might run out. HTTP/2 effectively removes this limit, but if you need to support older environments, you can't completely ignore it.

And if you need to send binary data or truly need bidirectional communication, WebSocket is obviously the way to go.

The bottom line

Chat, games, realtime collaboration tools where you need bidirectional -- WebSocket. Notifications, feed updates, dashboard refreshes where the server just pushes -- SSE. That's really all there is to it.

But I suspect plenty of people go down the same detour I did because of the "realtime = WebSocket" assumption. To save yourself 3 days of yak-shaving, ask whether you actually need bidirectional communication first.

Related Posts