WhatsApp is one of those systems that sounds boring until you look at the numbers. A very small engineering team moved an enormous volume of messages for hundreds of millions of people. That combination, tiny team and huge scale, is the whole story. It only happens when the core design is simple and the hard problems are pushed to the right places.
Start with what a chat app actually has to do. Someone sends a message. If the recipient is online, they should get it in well under a second. If they are offline, the message has to wait somewhere and be delivered the moment they reconnect. You need to show sent, delivered, and read states. And ideally the server should not be able to read the messages at all. That last requirement changes everything, so let me come back to it.
The first design decision is the connection model. A messaging app cannot work on request and response alone, because the server needs to push a message to you the instant it arrives, without you asking. So every client holds a persistent connection to the server, and messages flow over it in both directions. WhatsApp historically used a trimmed down version of XMPP over long-lived connections. The exact protocol matters less than the idea: keep a socket open, keep it cheap, and keep millions of them alive per machine.
That "millions per machine" part is why WhatsApp is famous for using Erlang. Erlang was built for telecom systems that hold huge numbers of concurrent connections and stay up for years. Its lightweight processes and its "let it crash" philosophy map almost perfectly onto "millions of open sockets, isolate failures, never take the whole node down." You could build this on other stacks today, but Erlang gave them an enormous head start on the one axis that mattered most.
Now the messaging logic itself. When you send a message, it goes to the server, which finds the connection for the recipient. If they are connected, it pushes the message straight through and the message never needs to be stored long term. If they are offline, the server holds the message in a queue keyed to that user and delivers it on reconnect, then deletes it. This is a key point that surprises people: WhatsApp does not keep your message history on its servers the way a social feed keeps posts. The message is a hot potato. It exists on the server just long enough to reach the other device, then it is gone. Your history lives on your phone.
Delivery receipts fall out of this naturally. One tick means the server accepted it. Two ticks mean the recipient's device acknowledged receipt. Blue ticks mean the recipient's app reported it was read. Each of these is just an acknowledgment traveling back up the same connection, and each is a small state update.
Then there is end to end encryption, which WhatsApp rolled out using the Signal protocol. This is the decision that constrains the rest of the design in a good way. Because messages are encrypted on your device with keys the server never has, the server genuinely cannot read them. It becomes a dumb, fast router of opaque blobs. That simplifies the server's job, since it is not doing content processing, and it means the "store until delivered" queue is holding ciphertext. The trade-off is that anything requiring the server to understand message content, like server-side search, is off the table by design. They accepted that on purpose.
A couple of trade-offs worth being honest about. Keeping history on the client makes the backend lean but makes multi-device and backup genuinely hard, which is why those features took years and involve careful key management. And holding persistent connections for everyone means your capacity is bounded by concurrent connections, not by request rate, so your scaling story is about connection density and graceful failover rather than raw throughput.
How does the real WhatsApp do it? Persistent connections, a lean message router that treats undelivered messages as short-lived queued items rather than permanent records, Erlang for connection density and fault isolation, and the Signal protocol for encryption that turns the server into a blind relay. The genius was not one clever trick. It was refusing to make the server do work it did not have to do.
That restraint is the real lesson. Most scaling problems are self-inflicted. WhatsApp scaled by carefully deciding what not to build.
I wrote the full breakdown, with diagrams and the data model, here: https://www.systemdesign.academy/interview/design-whatsapp
Top comments (0)