AlgoPlusAlgoPlus
Learn/System Design
Lesson

Design WhatsApp (Chat)

Real-time messaging with persistent connections, in-memory routing, store-and-forward for offline users, delivery receipts, and end-to-end encryption.

11 min read Watch it move Build it

WhatsApp delivers a message from one phone to another in real time, reliably, even when the recipient is offline — and privately. It famously scaled to hundreds of millions of users with a tiny team on Erlang/OTP + FreeBSD. The design turns on one requirement: the server must push to the recipient, not wait to be polled.

Why polling fails, and what replaces it

The naive design has the recipient periodically ask 'anything new?'. Most of those polls return nothing yet hammer the servers, and messages still arrive seconds late. Chat needs server→client push. The fix is a persistent connection: each phone keeps one long-lived socket open to the server, so the server can push the instant a message arrives.

Persistent socket ≠ WebSocket (for WhatsApp)
The generic answer is 'use a WebSocket'. WhatsApp's phone apps actually speak a compact binary protocol derived from XMPP/ejabberd over a TLS socket — it uses WebSocket only for the Web client. Either way the principle is the same: one persistent, push-capable connection per user.

One lightweight process per connection

WhatsApp runs one Erlang process — a tiny independent task — per connection, holding that user's session. Erlang processes are cheap, so a single machine holds an enormous number: Rick Reed reported ~2M connections (peak 2.8M) on one machine in 2012. To deliver to an online user, the backend hands the message between Erlang processes directly, using Erlang's built-in message passing — Reed reported >70M messages/sec on >8,000 cores in 2014.

The runtime is the messaging fabric
'Who is connected where' lives in Erlang's in-memory storage (Mnesia/ets), not Redis, and there is no separate broker or Kafka. The Erlang runtime itself routes the messages. The common 'WebSocket gateway + Redis presence + Kafka' diagram is *not* how WhatsApp's server actually works.

Offline: a message queue per user (store-and-forward)

If the recipient is offline, the server holds the message — encrypted — for up to 30 days, retrying delivery. This is store-and-forward: a per-user queue of undelivered messages. Once it gets through, the server delivers it and deletes it — WhatsApp keeps no copy of delivered messages.

  1. 1Sender pushes a message up its socket to the server.
  2. 2Server checks Mnesia: is the recipient online?
  3. 3Online → hand it to the recipient's Erlang process, which pushes it down that socket.
  4. 4Offline → queue it (encrypted, ≤30 days) and retry until it lands, then delete it.

Delivery receipts and end-to-end encryption

Those familiar ticks are the delivery state machine: one check = the server received it, two checks = delivered to the recipient's device, two blue checks = read. Privacy comes from the Signal Protocol, on by default for everyone since April 2016. End-to-end means only the two phones hold the keys; the server only ever sees ciphertext it cannot read. The server's job is to hand out users' public prekey bundles and relay encrypted media via a blob store; group messages are fanned out server-side, still as ciphertext (Sender Keys).

OperationTimeSpace
Poll (v1) · empty polls, seconds of lagwastefulO(1)
Deliver to online user · process-to-process pushO(1)O(1)
Deliver to offline user · store-and-forward ≤30 daysO(1) on reconnectO(queued msgs)
Check yourself
What does WhatsApp's server do with a message for a user who is currently offline?