A look at how WhatsApp works. WhatsApp sends roughly 100 billion messages a day for nearly 3 billion users, with end-to-end encryption on by default and a total engineering team that hovered around 50 people during its first billion users. The architecture that pulls this off is one of the cleanest examples of “pick the right substrate and let it do the work” in production, and it’s built almost entirely on Erlang.

How WhatsApp Works: The problem at scale
WhatsApp’s constraint isn’t throughput per message: a single message is a few kilobytes of ciphertext. The constraint is concurrency. At 100 billion messages a day and roughly 3 billion monthly active users, the system has to hold open ~10 million simultaneous TCP connections per data center, route each message to the right recipient device within a second, do it again when the recipient replies, and never lose a message in transit. Most web stacks die long before this: they allocate a thread per connection, hit the OS thread ceiling at a few thousand sockets, and collapse.
The second constraint is trust. Messages must arrive even when the recipient’s phone is in airplane mode, even when they switch devices, even when the network drops mid-send. And the plaintext must never touch a WhatsApp server: not in memory, not in logs, not in backup. Those two constraints (cheap concurrency at planet-scale, plus durable delivery of ciphertext) are the architectural decisions the whole system is built around.
The core architecture
Walk the diagram above from sender to receiver. The sender’s phone opens one long-lived TLS connection to WhatsApp’s connection layer, a fleet of Erlang/OTP nodes that hold sockets alive and multiplex them. When the sender submits a message, the client encrypts it locally with the Signal Protocol using keys derived from the recipient’s public identity; only the ciphertext leaves the phone. The connection layer hands the ciphertext to the message router, which is the interesting piece: a per-recipient Erlang process that owns the delivery state for that recipient. If the recipient has an active socket, the router pushes the ciphertext straight down it. If not, the router parks the message in the offline queue for up to 30 days and triggers a push notification. When the recipient’s phone reconnects, the queue drains and the client decrypts locally.
Why Erlang, and why that matters
The single most important design decision in WhatsApp is the runtime. Erlang was built by Ericsson in the 1980s for telephone switches, and its virtual machine (BEAM) gives you three things almost no other mainstream runtime gives you together: processes that cost ~300 bytes each (so you can spawn one per connection without thinking), preemptive scheduling (no single long request can starve others), and supervision trees (when a process crashes, its supervisor restarts it cleanly without affecting any other connection). WhatsApp’s fleet at scale held millions of Erlang processes per node, each owning one connection’s state. A Java or Go server trying the same thing would burn gigabytes of stack and need a thread pool tuned to the OS limit.
The folklore number: at acquisition time in 2014, WhatsApp had 450 million active users and 32 engineers. Erlang’s leverage is the entire reason that ratio was possible.
End-to-end encryption as an architectural constraint
Since 2016, every WhatsApp message uses the Signal Protocol (X3DH for key agreement, Double Ratchet for forward secrecy). The architectural impact is bigger than the cryptographic one: WhatsApp’s servers can never inspect message content, because they never have the keys. That means no server-side spam filtering on content, no server-side search through message bodies, no server-side ad targeting. The product had to be designed around what a routing-only server can do, and the result is a thinner, faster, and more private system than any of its competitors.
Multi-device (post-2021) is the harder version. Each device now gets its own key pair, all linked to the same account identity. Sending a message to “Alice” means sending it separately to Alice’s phone, her laptop, and her iPad, each with its own ciphertext derived from that device’s key. The per-recipient Erlang process now fans out to N sockets per user, and the queue is per-device, not per-account.
The one non-obvious insight
WhatsApp’s famous single-grey-tick / double-grey-tick / double-blue-tick state machine is not a UI feature. It’s a protocol. The sender’s phone learns about each state transition because the recipient’s phone, on decrypt, sends an acknowledgment ciphertext back through the same Erlang pipeline. That ack is itself a routed message, not a separate RPC. Everything in the system (messages, read receipts, typing indicators, presence) flows through the same per-recipient-process abstraction. There’s no “notifications service” bolted on the side; it’s all the same Erlang message bus.
This is why a 50-engineer team could run a billion-user product. They didn’t build many systems. They built one well.
What the architecture optimizes for, and what it gives up
The trade-off WhatsApp explicitly accepted: the system is brilliant for routing ciphertext to online or temporarily-offline recipients, and weak for anything that needs to inspect content server-side. WhatsApp Web’s first versions worked by mirroring the phone (the browser was a thin client over the phone’s actual connection), precisely because the server had no plaintext to give it. Cloud backup encryption is bolted on separately, and that’s where the model has historically leaked. The architecture is honest about its priorities: deliver messages fast, deliver them privately, do nothing else.
WhatsApp is what happens when a small team picks the exact right runtime for the concurrency profile of their problem and refuses to add anything that doesn’t fit the model. 100 billion messages a day on Erlang, with keys that never leave the devices. The folklore is real: the architecture is the moat.