“Design WhatsApp” sounds like a backend question, but in a mobile system design round the interviewer wants to see you think about the client. The hard problems are not at the data center — they are in your pocket: a flaky LTE connection, a battery you cannot drain, an OS that kills you in the background, and a user who expects messages to never duplicate, never disappear, and never arrive out of order.
Functional requirements
- Send and receive 1:1 and group messages with text, images, and voice notes
- End-to-end encryption (Signal Protocol)
- Read receipts and typing indicators
- Message history syncs across devices
- Works offline; queues messages and delivers when network returns
Non-functional
- Sub-second p99 message delivery in good network
- Battery: messaging in the background must not noticeably drain battery
- Storage: years of message history without filling the phone
High-level architecture
Three layers on the device: UI, message store (local SQLite or Realm), and sync layer (WebSocket persistent connection + REST fallback). The message store is the source of truth for the UI; the sync layer reconciles with the server.
Server side: a long-poll/WebSocket gateway, a message broker (Kafka), per-user mailbox storage, and a push notification fanout service.
The hard parts
Message ordering and idempotency
Each message has a client-generated UUID and a logical timestamp. The server orders messages within a conversation by Lamport-clock-style sequence numbers. Duplicate UUIDs are dropped at the server. The client also dedupes on receive in case it gets the same message twice from server push and from sync.
Offline send
Messages composed while offline go into an outbox table with status pending. A background worker drains the outbox when network returns, marks messages sent, and then transitions to delivered and read as receipts arrive.
End-to-end encryption
Signal Protocol with X3DH key agreement and Double Ratchet for forward secrecy. Each device gets its own identity key. New devices join via fan-out: the existing devices encrypt and re-distribute history.
Multi-device sync
The server stores ciphertext per recipient device. Read receipts and message state changes are also encrypted and synced. Conflict resolution is last-writer-wins with a logical clock.
Battery
Persistent socket only when the app is foreground or recently active. In the background, rely on the OS push notification system (APNs on iOS, FCM on Android) for wakeups. WebSocket reconnection uses exponential backoff with jitter.
Storage
SQLite with FTS5 for search. Old media is archived to cloud and downloaded on demand. Messages older than N days can be evicted from local storage with a “Tap to download” UX.
Frequently Asked Questions
How do you handle group messages with E2E encryption?
Sender encrypts the message with a sender key shared with all group members. When membership changes, the sender key rotates. Some implementations use pairwise encryption per recipient instead, which simplifies key management but increases bandwidth.
How do read receipts work without breaking E2E?
Read receipts are themselves encrypted messages sent back to the original sender. The server only sees opaque blobs.
What happens when the user reinstalls the app?
Identity keys are regenerated. The user re-registers, and the prior chat history can be restored from an encrypted cloud backup (iCloud Keychain, Google Drive) or recovered from another logged-in device.