Design Chat System
Design a chat system like WhatsApp or Slack: real-time messaging, presence, and group chat at scale.
What is a chat system?
A chat system accepts a message once, stores it durably, orders it within one conversation, and makes it available to every intended recipient device. A live WebSocket makes delivery feel immediate, but the durable conversation log is what lets the system recover after a disconnect, retry, or server failure.
The central invariant is: after the sender receives an accepted acknowledgement, retrying the same client message ID cannot create another logical message, and every reader observes one stable conversation sequence. Presence, typing indicators, and push notifications improve the experience, but none of them may decide whether a durable message exists.
Durability
Commit before accepted
Authorize, deduplicate, assign the conversation sequence, and commit the message plus its outbox event before telling the sender it was accepted.
Correctness
Order one conversation
Give each conversation one logical sequencing owner. Global ordering across unrelated conversations is unnecessary and expensive.
Recovery
Replay after failure
Clients reconnect with a durable cursor, fetch missing sequence ranges, and apply messages idempotently before resuming the live stream.
Attempt the design challenge before opening the walkthrough. Define what an acknowledgement means, draw the reconnect path, and state which features may degrade without blocking message acceptance.
What are chat-system requirements?
Requirements define the user promise before infrastructure choices begin. For this interview, a message is a durable logical record; a WebSocket frame, push notification, and per-device delivery are separate events.
Functional requirements
- Send and receive text messages in 1:1 conversations and groups of up to 256 members.
- Show ordered conversation history with cursor-based pagination.
- Support several devices per user and synchronize missed messages after reconnect.
- Expose accepted, delivered, and read states without creating one mutable row per recipient-message pair.
- Show approximate presence and typing indicators.
- Upload media out of band, then send a message containing an authorized media reference.
Non-functional goals
<100ms
Delivery latency
Target p95 for online users in one region
99.99%
Availability
Target for durable send and history APIs
50M
Connections
Assumed peak concurrent sockets
Per conversation
Ordering
No global message order
- Once
acceptedis returned, the message survives a process or gateway restart. - A retry with the same
(sender_id, client_message_id)returns the original message ID and sequence. - Messages are totally ordered inside one conversation; presence, typing, and read indicators may converge eventually.
- Authorization is checked when accepting a send and again when serving history.
- Overload may delay fanout or disable optional signals, but it must not acknowledge an uncommitted message.
Questions to ask the interviewer
- Does "delivered" mean one user device received the event or every registered device did? Assume at least one active device.
- Must a user see the same order on every device? Assume yes, using the server sequence.
- Are edits, deletes, reactions, search, calls, and end-to-end encryption required now? Treat them as extensions represented by ordered events.
- Can a temporarily unavailable conversation owner reject or queue sends instead of accepting them out of order? Assume yes.
- How long is hot history retained? Assume 30 days hot and one year archived.
Scope boundary
The core design includes durable text messaging, media references, groups, multi-device sync, receipts, presence, and push fallback. Full-text search, voice/video, public channels, bots, legal retention workflows, and end-to-end encryption key management are discussed as extensions rather than hidden inside the first design.