Design a Chat App like WhatsApp or Messenger
Deliver one-to-one and group messages in real time, even to offline users.
Asked at Meta, Microsoft and 3 more
3 min read·9 sections
A chat app delivers messages between people in real time: one-to-one, in groups, across phones and laptops, and to people who are offline right now. WhatsApp, Messenger and Slack all solve the same core problems: persistent connections, message routing, ordering and delivery guarantees.
Requirements#
Functional
- One-to-one and group chats (up to a few hundred members).
- Messages arrive in real time when the recipient is online.
- Offline users receive messages when they reconnect, plus a push notification.
- Sent, delivered and read receipts; online presence.
Non-functional
- Delivery latency under 200 ms when both users are online.
- Messages are never lost and appear in the same order for everyone.
- Hundreds of millions of concurrent connections.
Connections#
HTTP polling wastes battery and adds delay. Clients keep a WebSocket (or MQTT) connection open to a chat server, so either side can send at any time.
Sending a message#
- Alice's app sends the message with a client-generated ID over her socket to chat server 1.
- Server 1 assigns a sequence number within the conversation and writes it to the message store.
- It acknowledges to Alice (one tick: sent).
- It looks up Bob in the session registry, finds server 7, and forwards the message over the message bus.
- Server 7 pushes it to Bob's socket. Bob's app acknowledges, which flows back as "delivered" (two ticks).
- If Bob is offline, the message waits in storage and a push notification goes out.
Storing messages#
Chat is write-heavy and read by conversation, newest first. A wide-column store like Cassandra or HBase fits:
partition key: conversation_id
clustering key: message_seq (descending)
columns: sender_id, body, created_at, client_msg_idPartitioning by conversation keeps each chat's history on one partition, so loading the latest 50 messages is one sequential read.
Ordering and duplicates#
- Ordering: wall clocks differ across devices, so don't sort by client time. Assign a per-conversation sequence number on the server (for example, a counter per conversation in Redis, or the conversation's partition leader).
- Duplicates: networks retry. The client message ID makes the write idempotent: a repeated send with the same ID is acknowledged but not stored twice.
Group chats#
For small groups, the server fans out the message to each member's connection or offline queue. For very large channels, store one copy and let members pull, as with a social feed.
Offline sync and multiple devices#
Each device remembers the last sequence number it has seen per conversation. On reconnect it asks "give me everything after seq 1042", which also handles a phone and a laptop being in sync.
Presence#
Clients send a heartbeat every 30 seconds or so; a user is online if their last heartbeat is recent. Broadcast presence changes only to the user's contacts who are currently online, and batch them to avoid storms when a chat server restarts.
End-to-end encryption#
With E2EE (the Signal protocol), the server only routes ciphertext. That shapes the design: search, link previews and spam filtering must happen on the device.
Finished this walkthrough?
Mark it as read to track your progress in the list.