RSS Amplifier

Better Engineers · Aug 1, 2026

How WhatsApp Handled 1 Billion Users with 50 Engineers

0
Sign in to vote or save

Better Engineering · Better Engineers

In 2014, Facebook paid $19 billion for WhatsApp.

At the time, WhatsApp had 450 million users, was growing by 1 million users per day, and was processing 50 billion messages daily. The engineering team maintaining this infrastructure: 50 engineers.

For comparison: Twitter had ~3,000 engineers at similar scale. Facebook itself had over 6,000.

WhatsApp’s ratio of users per engineer was roughly 10 million to one ,the most efficient large-scale system ever built.

WhatsApp made a series of technical decisions that most engineers never learn about:

  • They chose Erlang when everyone used Java

  • They chose FreeBSD when everyone used Linux

  • They built on ejabberd when everyone wanted to build from scratch

  • They chose to do one thing when every competitor added features

Lets understand each decision made by WhatsAPP in this series , the Erlang actor model, Mnesia, FreeBSD kernel tuning, the custom XMPP protocol, message delivery flow, end-to-end encryption with Signal Protocol, and the engineering culture behind it all.

Before any technology, WhatsApp had a philosophy. Three principles that governed every decision:

1. Keep it very simple. The codebase, the architecture, the product. Simplicity at every layer.

2. Don’t reinvent the wheel. Build on open source. Use commercial solutions. Write only what gives you competitive advantage.

3. Use proven, solid technologies. Not the newest. Not the trendiest. Whatever works best for the specific problem.

These principles explain every technical choice that follows. Erlang isn’t new. ejabberd isn’t custom. FreeBSD isn’t modern. But all three were exactly right for WhatsApp’s specific problem: millions of persistent connections, low latency message delivery, high availability, tiny team.

WhatsApp’s backend is built on Erlang running on the BEAM virtual machine, using a modified version of XMPP via Ejabberd for messaging and presence, and Mnesia as the primary distributed database. This stack enables WhatsApp to handle billions of concurrent connections with low latency.

Erlang was created in 1987 by Ericsson for telephone switching systems — networks that must handle millions of simultaneous calls and absolutely cannot go down. It’s a functional language. Most engineers have never written a line of it. Its ecosystem is tiny compared to Java or Python.

WhatsApp chose it anyway. Here’s why.

In Java or C++, handling concurrent connections means OS threads. Each thread costs 1–8MB of memory and requires the OS to save the entire CPU state on every context switch. At 10,000 concurrent connections, you’re already using gigabytes of RAM just for thread overhead.

Erlang’s model is different. Instead of OS threads, Erlang has lightweight processes — isolated units of computation managed entirely by the BEAM virtual machine. Each process costs roughly 300 bytes of memory. Starting one takes microseconds. The BEAM scheduler handles switching between them with no OS involvement.

OS Thread model (Java/C++):
Each connection = 1 thread = 1-8MB RAM
10,000 connections = 10-80 GB RAM (just overhead)
Context switch = OS must save full CPU state

Erlang process model:
Each connection = 1 process = ~300 bytes RAM
2,000,000 connections = 600 MB RAM (just overhead)
Context switch = BEAM scheduler, microseconds

This is why WhatsApp scaled to 2 billion users with 50 engineers by using Erlang — lightweight processes handling 2M+ connections per server.

In WhatsApp’s architecture, every active user connection gets its own Erlang process. When Alice sends a message to Bob, the message passes directly from Alice’s process to Bob’s process via Erlang’s message-passing primitives — no locks, no shared memory, no coordination overhead.

% Simplified: Alice’s process sends to Bob’s process

% Bob’s process receives and forwards

Erlang’s OTP (Open Telecom Platform) provides supervision trees — a hierarchy of processes where parent processes monitor their children. When a child process crashes (due to a bad message, a network timeout, anything), the supervisor restarts it automatically.

Supervisor (never crashes, just restarts)
  ├── Connection Handler 1 (crashed? restart)
  ├── Connection Handler 2 (crashed? restart)
  ├── Message Router (crashed? restart)
  └── Presence Manager (crashed? restart)

This is the “let it crash” philosophy: don’t write complex error handling code. Let processes fail cleanly, and let supervisors bring them back. The system as a whole stays healthy even as individual components fail and recover. WhatsApp’s uptime was legendary precisely because of this design — individual user connection processes could crash and restart without affecting anyone else.

Read the original on betterengineers.substack.com

Comments

Nothing yet. Say the first thing.

    Sign in to join the conversation.