Design a chat app like WhatsApp

Chat needs low latency, reliable delivery and millions of open connections. We walk through the design step by step.

Chat bubbles flowing between phones and servers

Goal: users send text messages one-to-one and in groups, in real time, with delivery status.

Requirements

  • 1-to-1 and group chat, with sent/delivered/read status.
  • Messages must not be lost, and keep their order within a chat.
  • Offline users receive messages when they return.
  • Low latency (well under a second) and many concurrent connections.

Estimates

Say 50 million daily users sending 40 messages a day: 2 billion messages a day, about 23,000 messages/s on average. At 100 bytes each, that is about 200 GB of text a day. Media (images, voice) goes to object storage and only a reference travels in the message.

Connections

Each online user keeps a WebSocket to a chat server. A server may hold hundreds of thousands of connections. A session service (Redis) maps user -> chat server, so we know where to deliver.

Sending a message (1-to-1)

  1. Sender's app sends the message to its chat server over the WebSocket, with a client-generated message ID.
  2. The server stores the message durably (and acknowledges the sender: "sent").
  3. It looks up the recipient's chat server and forwards it. If the recipient is online, it is pushed over their socket, and they send a "delivered" ack back.
  4. If the recipient is offline, the message stays in storage, and a push notification is sent. When they reconnect, the app syncs everything after its last message ID.

Ordering and duplicates

Order messages per conversation with a sequence number or time-ordered ID assigned by the server. Because acks can be lost and clients retry, the message ID makes sends idempotent and prevents duplicates.

Storage

Write-heavy and ordered by conversation and time. A wide-column or key-value store partitioned by conversation_id suits it (Cassandra, DynamoDB style). Keep recent messages hot and archive old ones.

Group chat

On send, the server fans the message out to each member's inbox. For small groups, fan-out at write time is fine. For very large groups, store once and let members fetch.

Other concerns

  • Presence (online/last seen): heartbeats, stored with short expiry in Redis.
  • End-to-end encryption: the server stores and relays ciphertext it cannot read; keys live on devices.
  • Media: upload to object storage with a presigned URL, send the link.

Takeaway: WebSocket gateways, a session map, durable storage first then delivery, client message IDs for idempotency, and per-conversation ordering.


System Design series, Part 3 (case studies): 3 of 16. Previous: Design Pastebin: storing and sharing text snippets.

Keep reading