This article was originally published on AI Study Room. For the full version with working code examples and related articles, visit the original post.
WebSocket vs SSE vs Polling: Real-Time Data Patterns for Web Apps
Real-time features — live chat, notifications, dashboards, collaborative editing — each need a different data delivery pattern. WebSocket, Server-Sent Events (SSE), and polling solve different problems. Here's when to use each, with code examples.
Quick Comparison
| WebSocket | SSE (Server-Sent Events) | Short Polling | Long Polling |
|---|---|---|---|
| Direction | Bidirectional | Server → Client only | Client → Server (request/response) |
| Latency | Near real-time | Near real-time | Depends on interval |
| Browser support | All modern | All (except IE) | Universal |
| HTTP/2 friendly | N/A (upgrades from HTTP) | Yes | Yes |
| Reconnection | Manual (build it) | Built-in (automatic) | Manual |
| Complexity | High | Low | Lowest |
WebSocket — Bidirectional Real-Time
WebSocket is the only option when both client and server need to push messages. Use it for: chat applications, collaborative editing, multiplayer games, live auctions, trading platforms.
// Server (using ws)
import { WebSocketServer } from "ws";
const wss = new WebSocketServer({ port: 8080 });
wss.on("connection", (ws, req) => {
const userId = authenticate(req);
ws.on("message", (data) => {
const message = JSON.parse(data.toString());
// Broadcast to all clients in a room
wss.clients.forEach((client) => {
if (client.readyState === WebSocket.OPEN) {
client.send(JSON.stringify({ user: userId, text: message.text }));
}
});
});
ws.on("close", () => {
// Handle disconnect
});
});
Server-Sent Events (SSE) — Simple Server Push
SSE is simpler than WebSocket when you only need server → client updates. Built-in reconnection, works over HTTP/2, and doesn't need a special protocol. Use for: live dashboards, notification feeds, progress bars, log streaming, sports scores.
// Server (Hono)
app.get("/events", (c) => {
return c.streamText(async (stream) => {
// Send events as they happen
stream.write(`data: ${JSON.stringify({ type: "connected" })}
`);
const interval = setInterval(async () => {
const updates = await getUpdates();
stream.write(`data: ${JSON.stringify(updates)}
`);
}, 1000);
// Auto-cleanup on client disconnect
stream.onAbort(() => clearInterval(interval));
});
});
// Client (native EventSource — zero dependencies)
const es = new EventSource("/events");
es.onmessage = (event) => {
const data = JSON.parse(event.data);
updateUI(data);
};
Short Polling — Simplest, Least Efficient
Client sends a request every N seconds. Simple but wasteful — most requests return empty. Only use when you can't use SSE or WebSocket (e.g., legacy infrastructure) or when data changes very infrequently.
// Client — poll every 30 seconds
setInterval(async () => {
const res = await fetch("/api/updates?since=" + lastUpdate);
if (res.ok) {
const updates = await res.json();
if (updates.length) updateUI(updates);
}
}, 30000);
Long Polling — Polling Without the Waste
Client sends a request, server holds it open until there's new data (or a timeout). The client immediately reconnects after receiving a response. This is how most "real-time" APIs worked before WebSocket existed.
Best for: Legacy systems that can't upgrade to WebSocket, firewalls that block WebSocket connections, APIs where the client can't maintain persistent connections.
Decision Matrix
| Feature | Best Pattern | Why |
|---|---|---|
| Chat / messaging | WebSocket | Bidirectional, low latency |
| Live dashboard / feed | SSE | Simpler than WebSocket. Built-in reconnect. HTTP/2 friendly. |
| Notifications | SSE or Web Push | SSE if browser is open. Web Push for background notifications. |
| Progress bar / file upload | SSE | Push progress from server. Simple to implement. |
| Collaborative editing | WebSocket (or CRDT) | Low latency bidirectional required. |
| Simple status check | Short Polling | If data changes every 5+ minutes, polling is fine. |
Bottom line: Use SSE for server→client streaming — it's simpler than WebSocket, HTTP/2 friendly, and has built-in reconnection. Use WebSocket only when you need bidirectional communication. Use polling only as a last resort. Server-Sent Events is the most underrated real-time pattern. See also: Backend Framework Comparison and Edge Functions Comparison.
Read the full article on AI Study Room for complete code examples, comparison tables, and related resources.
Found this useful? Check out more developer guides and tool comparisons on AI Study Room.
Top comments (0)