Design WhatsApp: Fan-Out, Delivery & Encryption at Planetary Scale
WhatsApp moves over a hundred billion messages a day for more than three billion people. Here is how to design it in an interview: the connection map, the group fan-out multiplier, at-least-once delivery with ordering, and the encryption that makes the server blind.
Explain it like I’m five
Imagine a giant post office where every letter has to arrive in one second. You write a note, fold it into a paper plane, and it lands in your friend’s pocket — even if she is on another continent, even if her phone was asleep. Now imagine three billion people sending paper planes all day, and groups where one plane has to land in a thousand pockets at once.
That post office has four jobs. It always knows where everyone is standing right now. It copies each plane for every person in the group. If someone is asleep, it keeps their copy until they wake up. And it seals every plane so that only the person it is addressed to can open it — not even the post office can peek inside. Everything in this guide is how that post office works, written out.
Intuition: a connection problem, not a database problem
Most system-design answers start with tables. WhatsApp starts with pipes. Every phone holds a persistent, two-way connection to a server — a WebSocket that stays open so messages can flow either way at any moment, with no polling and no refresh. The hard part is not storing the messages. The hard part is holding hundreds of millions of those pipes open at once and knowing, at any instant, which server each person is attached to.
So think of the design as three layers. Presence and routing: a live map from every user to their server and socket. Fan-out: turning one sent message into one delivery per recipient, per device. Mailbox: holding messages for offline users until they reconnect. Storage exists, but it serves the mailbox — it is not the star of the show. And one more twist shapes everything: because messages are end-to-end encrypted, the server can route them but never read them. Privacy is a constraint on the architecture, not a feature bolted on later.
How it works: the map, the fan-out, the mailbox
Connections and the map. A fleet of connection servers does one job: babysit open WebSockets. When you open the app, a load balancer hands you to one of them, and the system records the mapping — user → server → socket — in a fast store keyed by user ID. To deliver a message, a server just asks: where is this person connected right now? The answer has to be milliseconds-fast, because every single message starts with that lookup.
Fan-out. One-to-one delivery is one lookup and one push. Group delivery is the multiplier: one message into a group of up to 1,024 members means up to 1,024 deliveries. Fan out from the sender’s server — push to every member who is online, queue for every member who is offline. Never do a thousand sequential database writes per message; the fan-out is a push problem, not a write problem.
Ordering and delivery promises. Networks drop and reorder things, so the system acknowledges everything: the server ACKs the sender, the receiver ACKs the server, and anything unacknowledged gets resent. That is at-least-once delivery — a message always arrives, possibly twice — so the client dedupes by message ID before showing anything. A per-conversation sequence number keeps ordering sane: even when retries arrive out of order, the chat renders in order.
Encryption. WhatsApp encrypts end to end with the Signal protocol: keys live on the devices, and each message is sealed before it leaves the sender’s phone. The server routes and stores only scrambled text it cannot read. That rules out server-side search, server-side spam scanning, and server-side translation — every content feature has to live on the client. Multi-device adds a wrinkle: each device holds its own keys, so the sender encrypts once per recipient device, and the server keeps a mapping from account to devices so senders can find them.
Presence, typing, and media. “Online” is a heartbeat: the app pings every so often, and missed pings mean offline. “Typing…” is an ephemeral event, not a message — never stored, never acknowledged, never retried; if it is lost, the indicator just expires. Media never touches the message store: the sender encrypts the photo or video on the phone, uploads it to blob storage, and the message carries only a pointer. Shard everything by conversation, so one chat’s history lives together and pages fast.
Switchboards of the real internet
WhatsApp. Built on Erlang, whose featherweight processes made each idle connection nearly free — a 2012 engineering post reported over 2 million concurrent connections on a single server. In 2016 it completed its rollout of Signal-protocol end-to-end encryption across all message types, and in 2021 it shipped multi-device support with per-device keys and sender-side encryption per device. The through-line: pick the runtime that matches the shape of the problem, then let product constraints (encryption, multi-device) reshape the architecture.
Telegram. Draws the storage line in two places: cloud chats live on Telegram’s servers, so history is everywhere instantly — while secret chats are end-to-end encrypted and live only on the two devices. Same switchboard, two trust models, and a standing reminder that storage and encryption are product decisions before they are engineering ones.
Discord. Runs its real-time layer on Elixir (Erlang’s modern cousin) and shards chat by guild, so one server’s explosion never takes down the rest. Same pipes-and-map architecture, different partitioning key.
Slack. The contrast case: a workplace tool where message-history search is a core feature, so messages must live on the server, indexed and searchable. WhatsApp is the opposite — delivery first, history on the device. Two products, two storage architectures, and the interview answer starts by naming which one you are building.
The fan-out math, by hand
More than three billion monthly users, more than a hundred billion messages a day: 100B ÷ 86,400 ≈ 1.2M messages/second on average. Peaks run roughly 2–3× average — New Year’s Eve, a World Cup goal — so provision for ~3M/sec. If every message were stored at ~1 KB with metadata, that is 100 TB/day of writes — one reason WhatsApp treats the server as a delivery pipeline, not an archive: once a message is delivered, the server has little reason to keep it.
Three patterns in Python
A fan-out that pushes to online members and queues for offline ones, a deduping store that keeps per-conversation ordering, and an ephemeral presence entry with a TTL — the three patterns behind almost every “how does the message get there safely” follow-up.
def fan_out(msg, members, registry, queue):
# one message in, one delivery per member: push or queue
for user in members:
conn = registry.lookup(user) # user -> server -> socket
if conn:
conn.push(msg)
else:
queue.enqueue(user, msg) # offline: drain on reconnect
class OrderedStore:
# at-least-once in, exactly-once in-order out
def __init__(self):
self.by_conversation = {}
self.seen_ids = set()
def store(self, msg):
if msg["id"] in self.seen_ids:
return False # duplicate retry: drop it
self.seen_ids.add(msg["id"])
conv = self.by_conversation.setdefault(msg["conv"], {})
conv[msg["seq"]] = msg # seq orders retries
return True
def history(self, conv, limit=50):
msgs = self.by_conversation.get(conv, {})
return [msgs[k] for k in sorted(msgs)[-limit:]]
def set_typing(presence, user, conv, ttl=5):
# ephemeral: no ACK, no retry, expires on its own
presence.set(f"typing:{conv}:{user}", 1, ex=ttl)
Six questions that test the real understanding
What to say (≈90 sec): “Start with the pipe: every client holds a persistent WebSocket to a connection server, and a fast map tracks which user is on which server. Sending is three hops: my server, a lookup, your server, down your socket. Scale: over 3 billion users, 100 billion messages a day, about 1.2 million a second on average. The scaling trap is group fan-out — one message into a 1,024-member group is 1,024 deliveries, so push to online members and queue for offline ones. Delivery is at-least-once with ACKs at every hop, client-side dedup by message ID, and per-conversation sequence numbers for ordering. Encryption is Signal-protocol end-to-end, so the server routes scrambled text it cannot read — no server-side search or moderation. Presence and typing are ephemeral, never stored. Media goes to blob storage with only a pointer in the message, and everything shards by conversation.”
Likely follow-up: “How do you handle a user with four devices?” — each device holds its own connection and its own keys; the fan-out treats a user’s devices like tiny group members, and the sender encrypts once per device.
What to say: “Per-conversation sequence numbers. The sender numbers its messages 1, 2, 3 in the conversation, and the client renders by sequence, not by arrival. A retry that arrives late slots into its sequence position. The server can enforce the numbering, but the client is the last line of defense — never trust arrival order on a network that reorders.”
What to say: “Because the server never sees plaintext. With Signal-protocol end-to-end encryption, keys live on the devices and the server stores only scrambled text. Server-side search would require the server to decrypt, which breaks the model. Search has to run on the client, over the local message history. Same reason there is no server-side spam scanning or translation — every content feature moves to the client.”
What to say: “It’s an ephemeral event, not a message — never stored, never ACKed, never retried. Keystrokes are noisy, so the client throttles: send ‘typing started’ at most every few seconds, and ‘typing stopped’ on send or after ~5 idle seconds. The server fans it out like a receipt but with a TTL — if the stop event is lost, the indicator just expires. Cheap, lossy, and nobody notices the loss.”
What to say: “The reconnect storm. If every offline user pulls their full queue the moment they reconnect, the queue becomes the bottleneck — and if a million users reconnect after an outage, it becomes a thundering herd. Cap the per-user queue, page the drain, and back off retries. And for a chat that is really a broadcast — a 1,024-member group where one person never reads — consider collapsing the queue: deliver from the last unread sequence number, not from message one.”
What to say: “Forwarding turns one send into a million fan-outs, which is the group problem at its worst. Three defenses: rate-limit forwards per sender, cap the fan-out burst per conversation, and treat forwarding as a pointer, not a copy — the forwarded message references the original media in blob storage instead of re-uploading it. The queue absorbs what the hot path can’t push immediately, and the per-conversation sequence numbers keep every recipient’s view ordered even when the burst lands out of order.”
Key takeaways
- WhatsApp is a connection problem, not a database problem: hold hundreds of millions of persistent pipes open, and keep a live map from every user to their server and socket.
- Group chats multiply load instead of adding it — one message, up to 1,024 deliveries. Push to online members, queue for offline ones, and respect the fan-out math when sizing the system.
- At-least-once delivery plus idempotent dedup plus per-conversation sequence numbers is the industry answer to “never lose a message, never show it twice, never show it out of order.”
- End-to-end encryption makes the server blind: it can route and store scrambled text, but every content feature — search, moderation, translation — has to live on the client.
- Presence and typing are ephemeral events, never messages. Media lives in blob storage with only a pointer in the message. Shard by conversation so one chat’s history is one range scan.
Sources & further reading
Every claim in this guide traces to one of these — the wording is ours, the ideas are credited.
- Signal blog: WhatsApp end-to-end encryption is complete (Signal Protocol rollout across all WhatsApp message types, April 2016)
- Meta Engineering: multi-device for WhatsApp (per-device identity keys, sender-side encryption per device, July 2021)
- WhatsApp engineering blog: “1 million is so 2011” (2M+ concurrent TCP connections on one server, Erlang, Jan 2012)
- WhatsApp statistics: users, messages, and growth (3B+ monthly users confirmed on Meta’s Q1 2025 earnings call; 100B+ messages a day)
- WhatsApp group limits, via the WhatsApp Help Center (up to 1,024 members per group)
- Designing Data-Intensive Applications — Martin Kleppmann (replication, partitioning, and stream processing patterns)