Skip to content
WebSockets and Server-Sent Events: Real-Time Communication Patterns 4 min

WebSockets and Server-Sent Events: Real-Time Communication Patterns

SD
ScaleDojo
May 11, 2026
4 min read1,029 words
WebSockets and Server-Sent Events: Real-Time Communication Patterns

The Problem: HTTP Is a One-Way Street

In 2012, Slack was struggling. Their chat app needed messages to appear instantly, but HTTP only works like sending letters: the client asks a question, the server sends an answer, done. Their early prototype polled the server every 2 seconds - 30 requests per minute per user, most returning 'nothing new.' With 10,000 users online, that was 300,000 useless requests per minute. The servers groaned under the load and messages still felt laggy.

This is the fundamental problem with HTTP for real-time applications: the server has no way to push data the moment something happens. The client has to keep asking. WebSockets and SSE exist to solve this.

WebSockets and Server-Sent Events: Real-Time Communication Patterns - Architecture Diagram
Architecture overview

Three Approaches Compared

Polling: Client keeps asking

  Client: Anything new?   Server: Nope.
  Client: Anything new?   Server: Nope.
  Client: Anything new?   Server: Yes! Here's a message.
  Client: Anything new?   Server: Nope.
  [30 requests/min, ~1s average latency]

SSE: Server pushes when ready (one-way)

  Client: I'm listening.  Server: ...waiting...
                           Server: Here's an event!
                           Server: Here's another!
                           Server: ...waiting...
  [1 persistent connection, 0ms latency, server-to-client only]

WebSocket: Full two-way pipe

  Client: Upgrade!        Server: OK, upgraded!
  Client: Chat message -> Server
  Server -> New message -> Client
  Client: Typing...    -> Server
  Server -> User online -> Client
  [1 persistent connection, 0ms latency, both directions]

WebSockets: A Two-Way Pipe

WebSocket is a protocol that starts as HTTP, then upgrades into a persistent, full-duplex connection. Both sides can send messages at any time.

The upgrade handshake looks like this:

GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Version: 13

--- Server Response ---

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=

After this handshake, the TCP connection stays open and both sides send lightweight frames back and forth. No HTTP headers on every message - just raw data with a tiny 2-6 byte frame header. This is why WebSockets are so efficient for high-frequency messaging.

WebSockets are ideal for:

  • Chat applications - messages flow both ways instantly (Slack, Discord, WhatsApp Web)
  • Multiplayer games - player actions and game state need constant bidirectional exchange
  • Collaborative editing - every keystroke needs to reach other editors immediately (Google Docs, Figma)
  • Trading platforms - order submissions (client to server) and price feeds (server to client) both need to be real-time

Server-Sent Events (SSE): One-Way Streaming

Sometimes you only need the server to push data to the client. The client never needs to send anything back through this channel (it can use regular HTTP for that). SSE is perfect for this.

SSE uses a regular HTTP connection that the server keeps open, sending events as they happen. The format is dead simple - just text lines:

// Client-side JavaScript - that's it!
const source = new EventSource('/api/live-prices');

source.addEventListener('price-update', (e) => {
  const data = JSON.parse(e.data);
  updatePriceDisplay(data.symbol, data.price);
});

// Server sends plain text events:
event: price-update
data: {"symbol": "AAPL", "price": 178.50}
id: 1042

event: price-update
data: {"symbol": "GOOG", "price": 141.20}
id: 1043

SSE advantages over WebSockets:

  • Works over standard HTTP - no special proxy configuration needed, passes through all firewalls and corporate proxies
  • Automatic reconnection - browsers automatically reconnect if the connection drops, and send the Last-Event-ID header so the server can resume from where it left off
  • Event IDs and types - built-in support for named events and sequence tracking
  • Simpler to implement - just stream text over HTTP. No frame protocol, no special libraries needed. Any HTTP server can serve SSE.

When to Use Which

Use Case             Best Choice    Why
------------------------------------------------------------
Chat / messaging     WebSocket      Bidirectional + low latency
Live notifications   SSE            Server-push only, simpler
Multiplayer gaming   WebSocket      Low-latency bidirectional
Live dashboards      SSE            Server pushes metrics
Stock ticker         SSE            Price feed is one-way
Collaborative edit   WebSocket      Both users send changes
Progress updates     SSE            Server reports status
IoT device control   WebSocket      Send commands + receive data

Scale Challenges

Both WebSockets and SSE maintain persistent connections. A server with 50,000 concurrent WebSocket connections needs to manage all those open sockets. This introduces challenges that do not exist with stateless HTTP:

  • Memory per connection - each connection uses ~20-50KB of memory. 100K connections = 2-5 GB just for connection state.
  • Load balancer stickiness - you cannot freely route a reconnecting client to a different backend server because its subscription state lives on the original server.
  • Horizontal scaling requires a pub/sub backbone - like Redis Pub/Sub or Kafka - so any server can push messages to any connected client regardless of which server holds the connection.
  • Connection storms - if a server restarts, all 50K clients reconnect simultaneously. Add jittered reconnection delays to prevent thundering herd.

Scaling WebSockets: The Architecture

              [Load Balancer]
             /       |       \
        [WS-1]   [WS-2]   [WS-3]    (WebSocket servers)
           \       |       /
            [Redis Pub/Sub]           (message backbone)
                  |
            [App Servers]             (business logic)

User A connected to WS-1 sends message to User B on WS-3:
1. WS-1 receives message from User A
2. WS-1 publishes to Redis channel for User B
3. Redis delivers to WS-3 (which subscribes to User B's channel)
4. WS-3 pushes the message to User B's WebSocket

Numbers That Matter

  • A single server can handle 100K-1M concurrent WebSocket connections with proper tuning (Linux file descriptor limits, epoll)
  • WebSocket frame overhead: 2-6 bytes vs HTTP header overhead: 200-800 bytes per request
  • SSE reconnection default: browsers retry after ~3 seconds with no extra code
  • Discord handles 6+ million concurrent WebSocket connections across their server fleet
  • Phoenix (Elixir) has demonstrated 2 million concurrent WebSocket connections on a single server

Interview Tip

When designing any real-time feature in an interview, explicitly choose between polling, SSE, and WebSockets. Say: 'For notifications I would use SSE because it is server-to-client only and simpler to scale. For chat I would use WebSockets because both sides send messages. In both cases I need a Redis Pub/Sub layer to route messages across horizontally scaled servers.' This shows you understand both the protocol choice AND the scaling implications.

Key Takeaway

WebSockets give you bidirectional real-time communication. SSE gives you server-to-client streaming over plain HTTP. Choose based on whether the client needs to send data back on the same channel. Both require a pub/sub backbone (like Redis) for horizontal scaling, and both need careful connection lifecycle management at scale.

Enjoyed this article?

Share it with your network to help others level up their system design skills.

Discussion0

Join the Discussion

Sign in to leave comments, reply to others, or like insights.

Sign In to ScaleDojo

No comments yet. Be the first to start the thread!

Related Articles

Enjoyed this content?

Your support keeps us creating free resources

We put a lot of hours into researching and writing these guides. If it helped you, consider buying us a coffee. Every bit goes toward keeping ScaleDojo's content free and growing.

$

One-time payment via Stripe. ScaleDojo account required.

ScaleDojo Logo
Initializing ScaleDojo