Long Polling vs WebSockets
Updated June 3, 2026When you need your web app to receive data from the server in near-real-time, you have two main options that most engineers reach for: long polling and WebSockets. The usual instinct is to go straight for WebSockets because they sound more "real-time." But that instinct leads to unnecessary complexity more often than you'd think.
Let's understand both, look at their actual trade-offs, and build a decision framework you can use.
Regular Polling: The Baseline
Before getting into long polling, it's worth understanding regular (short) polling, because it helps illustrate what problem we're solving.
Regular polling: the client makes a request every N seconds. "Any new messages?" → server responds → repeat.
Simple. Stateless. Works everywhere. But if there's nothing new 90% of the time, you're burning server resources on empty responses. And your "real-time" experience has a latency floor equal to your polling interval.
Long Polling: Held Connections
Long polling — request held open until data, client immediately re-polls
Long polling is a clever hack on top of the regular HTTP request/response model. Here's how it works:
- Client makes a request: "Any new data?"
- If there's data, server responds immediately
- If there's no data, the server holds the connection open — doesn't respond yet
- When data arrives, the server sends the response
- Client immediately makes another request
The connection is "long" because it stays open until something happens (or a timeout occurs, typically 30-60 seconds). From the client's perspective, new data arrives almost immediately when it's available.
This is what Facebook used for its chat system for years. This is what many notification systems use today. It's not glamorous, but it's remarkably effective.
In long polling, what does the server do when the client asks for new data and none is available yet?
// Client-side long polling loop
async function poll() {
try {
const response = await fetch('/api/updates?lastId=' + lastSeenId);
const data = await response.json();
handleUpdates(data);
} finally {
// Immediately start the next poll
poll();
}
}What you get:
- Near-real-time delivery (latency = time until server responds)
- Works through all proxies, firewalls, and load balancers
- Stateless on the server — any server can handle any poll request
- No special infrastructure required
- Easy to debug (it's just HTTP)
The costs:
- One HTTP connection per client at all times (but HTTP/2 helps)
- Server must hold open connections, which consumes file descriptors and memory
- Some overhead per request from HTTP headers
- Not great for very high message rates (each message = a full request/response cycle)
A major operational advantage of long polling over WebSockets is that long polling keeps servers stateless.
WebSockets: Persistent Bidirectional Connections
WebSockets — persistent bidirectional connection, Redis Pub/Sub for multi-server routing
WebSockets establish a persistent, full-duplex TCP connection between client and server. After an initial HTTP upgrade handshake, both sides can send messages at any time without the overhead of HTTP headers.
const ws = new WebSocket('wss://api.example.com/stream');
ws.onmessage = (event) => {
handleUpdate(JSON.parse(event.data));
};
ws.send(JSON.stringify({ type: 'subscribe', channel: 'prices' }));Once the connection is open, the server can push any number of messages in rapid succession with minimal overhead per message. The client can also send messages back. It's a real two-way channel.
What you get:
- True real-time, low-latency delivery
- Very low per-message overhead (no HTTP headers)
- Efficient for high message rates
- Full bidirectional communication
The costs — and they're real:
Infrastructure complexity. WebSocket connections are stateful and persistent. A connection lives on a specific server. If you have 10 servers and a user's connection is on server 3, a message meant for that user must be routed to server 3. This requires a message broker (Redis Pub/Sub, Kafka) to coordinate between servers.
Load balancing is harder. Regular HTTP load balancers work at the request level. WebSocket connections are long-lived, so load can become uneven over time as connections accumulate on certain nodes.
Proxies and firewalls. Some corporate firewalls block WebSocket connections. Some older proxies don't handle the upgrade handshake well.
Connection management. You need to handle reconnection, heartbeats to detect dead connections, and re-subscription after reconnecting.
Why do WebSocket deployments typically require a message broker like Redis Pub/Sub?
| Factor | Long Polling | WebSockets |
|---|---|---|
| Infrastructure | Standard HTTP servers | Requires WS-aware infra + message broker |
| Load balancing | Easy (stateless) | Harder (persistent connections) |
| Message rate | Low-medium | High |
| Bidirectional | No | Yes |
| Firewall friendliness | Excellent | Sometimes blocked |
| Debugging | Easy (HTTP tools work) | Harder |
| Server-sent data only | Good enough | Overkill if only server→client |
Server-Sent Events: The Often-Forgotten Middle Ground
Worth mentioning: Server-Sent Events (SSE) sit between long polling and WebSockets. It's a standard HTTP/2 feature where the server sends a stream of events over a single persistent connection — but it's one-way (server to client only).
SSE is simpler than WebSockets, works over plain HTTP, and handles reconnection automatically. If you only need the server to push updates to the client (no client-to-server messages), SSE is often the best choice.
Server-Sent Events (SSE) support full bidirectional communication between client and server.
The Decision Framework
Use long polling when:
- Message rates are low (a few per minute is fine)
- You need maximum compatibility (corporate networks, legacy proxies)
- Your servers are stateless and you want to keep them that way
- You're building an MVP and want to ship fast
- Delivery latency of 1-2 seconds is acceptable
Use SSE when:
- You only need server-to-client updates
- Message rates are moderate
- You want a persistent connection without full WebSocket complexity
Use WebSockets when:
- You need true bidirectional communication (client sends frequent messages too)
- Message rates are high (dozens per second or more)
- Latency must be sub-100ms
- You're building: multiplayer games, collaborative editing, live trading dashboards, live sports scores
The rule of thumb: Start with long polling or SSE. Migrate to WebSockets only when you have a concrete reason — measured latency requirements, high message rates, or genuine bidirectionality. The operational complexity of WebSockets is real, and most apps don't need it.
Slack used long polling for years. GitHub's live updates use long polling. Many chat systems run on long polling fine. Don't reach for complexity you don't need.
Which scenario is the best fit for WebSockets over long polling?
Summary
Long polling holds an HTTP request open until new data is available, then the client immediately makes another request. It delivers near-real-time updates, works everywhere, and keeps servers stateless — but isn't ideal for high message rates. WebSockets establish a persistent bidirectional connection, enabling true real-time with low per-message overhead — at the cost of stateful connections, complex load balancing, and a message broker requirement. Server-Sent Events offer a clean middle ground for server-to-client-only streams. Pick the simplest option that meets your latency and throughput requirements.
How helpful was this content?
Comments
Sign in to join the discussion
Saved on this device only
Sign in to sync progress across devices