WebSockets vs SSE vs Long Polling — Elige el patrón de tiempo real adecuado antes de que tu aplicación de chat se derrita
La mayoría de desarrolladores se quedan con WebSockets sin pensar. Esta comparación entre WebSockets, Eventos enviados por el servidor y polling prolongado cubre las verdaderas diferencias — latencia, comportamiento de reconexión, complejidad de infraestructura, bidireccionalidad — para que elijas el patrón adecuado y dejes de sobrediseñar tu flujo de datos.
You built a dashboard. Users need live data updates. You reached for WebSockets — because that’s what everyone does. Now you’re debugging sticky sessions at 2 AM because your load balancer keeps sending clients to the wrong pod. The data you’re pushing? A single JSON number every 10 seconds. WebSockets were overkill.
This happens constantly. Developers treat WebSockets as the default real-time solution, when SSE or long polling would have shipped faster, scaled more easily, and cost less to operate. Here’s how to actually choose.
The Decision Table
Before the deep dive, here’s the full comparison. Use this to make a call, then read the sections below if you need the reasoning.
| Característica | Long polling | Server-Sent Events | WebSockets |
|---|---|---|---|
| Protocolo | HTTP/1.1 | HTTP/1.1+ (chunked) | WS (HTTP upgrade) |
| Dirección | Client pulls only | Server → Client only | Full bidirectional |
| Soporte en navegadores | All browsers | All modern (no IE11) | Todos los modernos |
| Reconexión automática | Manual — you write the loop | Built-in via EventSource | Manual or via library |
| CDN / proxy friendly | Sí | Mostly (watch timeouts) | No |
| Horizontal scaling | Stateless, trivial | Stateless, trivial | Requires sticky sessions or pub/sub broker |
| Infra complexity | Low — plain HTTP | Low — plain HTTP | High — stateful connections, LB config, broker |
| Latency | Poll interval + round trip | Near real-time | Near real-time |
| APIs, microservicios, autenticación entre dominios | Low-frequency updates, legacy infra | Dashboards, feeds, notifications | Chat, collaborative editing, gaming |
Long Polling: The Unsexy Workhorse
Long polling is not “old” or “wrong” — it’s just HTTP. The client makes a request, the server holds it open until there’s something to say (or a timeout fires), the client gets the response and immediately fires the next request. Repeat.
It’s been around since before WebSockets existed and it still runs millions of production apps. The reason: it’s just HTTP. Your existing reverse proxy, CDN, load balancer, and monitoring all understand it without configuration. No sticky sessions, no protocol upgrades, no WS-aware infrastructure.
The downsides are real though. Every “update” is a full HTTP request cycle — headers, TCP overhead (unless HTTP/2), server-side request queuing. Under high concurrency this gets expensive on the server. And the latency floor is the round-trip time of each poll, not the latency of the event itself. If you’re polling every 5 seconds and an event fires at second 1, the user waits 4 more seconds.
When to use it: Legacy systems where adding a persistent connection layer isn’t worth the infra change. Low-frequency updates (once per minute or less). Environments where SSE gets killed by overzealous proxies. Polling that clients explicitly control — job status checks, async task results.
Server-Sent Events: The One Everyone Forgets
SSE is a standard (HTML Living Standard) that lets a server push a stream of text events over a single long-lived HTTP connection. The browser handles reconnection automatically. You don’t write a reconnect loop — the EventSource API just reconnects with the last event ID it saw, so you can resume a stream after a network blip.
The wire format is embarrassingly simple:
HTTP/1.1 200 OK
Content-Type: text/event-stream
Cache-Control: no-cache
id: 1
event: price-update
data: {"symbol":"BTC","price":67420}
id: 2
event: price-update
data: {"symbol":"ETH","price":3521}
Each event is plain text with optional id, event, datay retry fields, separated by blank lines. You can test SSE endpoints directly with cURL — use the Generador de Comandos cURL to construct the request with the right Accept header (text/event-stream) and stream the response.
On the client side:
const es = new EventSource('/api/events');
es.addEventListener('price-update', (e) => {
const payload = JSON.parse(e.data);
updateDashboard(payload);
});
es.onerror = () => {
// EventSource will auto-reconnect. You don't need to do anything here
// unless you want to log or update UI state.
};
SSE has one real limitation: it’s server-to-client only. The client can’t push data back over the same connection — any client-initiated actions go over normal HTTP requests. For most dashboard, notification, and feed use cases, that’s fine. You weren’t using the client-to-server direction anyway.
The other gotcha: some proxies buffer the response body and only forward it after the connection closes, which breaks streaming entirely. NGINX needs proxy_buffering off. Cloudflare’s free tier buffers SSE. If your infra has a buffering proxy in the middle and you can’t configure it, SSE won’t work and you’ll need WebSockets or long polling.
When to use it: Live dashboards, notification feeds, activity logs, AI response streaming (this is exactly what ChatGPT’s streaming API uses), stock tickers, deploy/build log tailing. Anywhere the server has data to push and the client doesn’t need to push back.
WebSockets: When They’re Actually Worth It
WebSockets give you a full-duplex, persistent connection over a single TCP socket. After the HTTP upgrade handshake, both sides can send framed messages at any time. The latency is as low as you can get over a network — no new request per message, no headers on each frame.
The tradeoff is that they’re stateful. The server needs to track every open connection. This immediately creates problems at scale: load balancers route by connection (not request), so you need sticky sessions or a pub/sub broker (Redis, etc.) to fan out messages across multiple server instances. Your CDN can’t cache WebSocket traffic. Your reverse proxy needs explicit configuration for the upgrade. Your monitoring needs to understand WS frames if you want payload-level visibility.
None of this is insurmountable, but it’s real work. When you’re starting a project and evaluating options, “it’s just HTTP” vs. “stateful WS connections with a Redis pub/sub layer” is a meaningful difference in complexity.
WebSocket payloads are typically JSON. If you’re debugging a WS integration and need to inspect or format the messages, the Formateador JSON makes it easier to read minified payloads from your dev tools network tab.
Cuándo usarlas: Chat applications (genuinely bidirectional — every message is client-initiated). Collaborative editing (Figma, Google Docs — multiple clients writing to shared state). Multiplayer games (high-frequency, low-latency state sync). Financial trading terminals (sub-100ms latency on order books). Basically: anything where the client needs to push data frequently, not just receive it.
The Scaling Gotcha Nobody Mentions Until It’s Too Late
Long polling and SSE are stateless at the HTTP layer. Each request can land on any server instance. Your horizontal scaling story is boring and that’s a feature: add more instances, done. Connection state lives only for the duration of the open HTTP connection, and load balancers route freely.
WebSockets are stateful. Client A’s connection lives on Server 1. When you want to push a message to Client A from Server 2 (because the event originated there), Server 2 has to know about that connection. The standard solution is a pub/sub broker — Redis pub/sub, Kafka, or managed services like Pusher or Ably that abstract all of this away. You either build that layer yourself or you pay for it.
Pusher charges $49/month for 500 concurrent connections. Ably is similarly priced. If your “real-time feature” is a notification badge that updates when someone likes your post, that’s a lot of money for SSE you could host for free alongside your existing API.
HTTP/2 Changes the Long Polling Math
Classic HTTP/1.1 long polling is one request per connection per in-flight hold. Under HTTP/2, multiplexing means multiple streams over one TCP connection. The overhead is lower. This isn’t a reason to pick long polling over SSE, but it means the “HTTP overhead is expensive” criticism applies less in 2024 than it did in 2012 when these comparisons were first written.
If you’re on HTTP/2 end-to-end (client to server, no intervening proxy that downgrades), long polling scales better than most older benchmarks suggest.
Quick Decision Guide
Stop reading here if your use case fits one of these cleanly:
- Update frequency < 1/minute, legacy infra, simple polling semantics: Long polling. Don’t complicate it.
- Server pushes data, client mostly reads, standard HTTP infra: SSE. This covers 80% of “real-time” features.
- Client sends data frequently, latency < 100ms matters, truly bidirectional: WebSockets. Now it’s worth the complexity.
- You’re using AI streaming (OpenAI, Anthropic, etc.): SSE — that’s literally what their streaming APIs use.
- Multiplayer game or collaborative editor: WebSockets, or a purpose-built framework (Liveblocks, PartyKit, etc.).
The default answer isn’t WebSockets. It’s SSE — until you have a specific reason it isn’t enough. The number of production apps that actually need full bidirectional real-time is much smaller than the number that Aunque WebSockets. That gap is engineering debt accumulated at 2 AM in front of a load balancer config.
Instalar extensiones
Agregue herramientas IO a su navegador favorito para obtener acceso instantáneo y búsquedas más rápidas
恵 ¡El marcador ha llegado!
Marcador es una forma divertida de llevar un registro de tus juegos, todos los datos se almacenan en tu navegador. ¡Próximamente habrá más funciones!
Herramientas clave
Ver todo Los recién llegados
Ver todoActualizar: Nuestro última herramienta fue agregado el 19 de junio de 2026
