On this page · sections
04. Design a Real-time Chat
Difficulty: Hard
Interview Focus: WebSockets · Message Ordering · Offline Sync · Presence
Interview Question
Design a real-time chat application that delivers messages instantly, handles reconnects, and keeps conversations consistent.
Requirements
Functional
- 1:1 and group conversations
- Send / receive messages in real time
- Typing indicators and online presence
- Delivery / read receipts (optional depth)
- Load older messages (pagination)
- Handle reconnect and offline send queue
Non-Functional
- Low latency delivery
- Correct ordering under concurrency
- Resilient reconnect
- Accessible message list and composer
- Scalable fan-out to many clients
Solution
1. High-Level Architecture
Chat UI
↓
Message Store
↓
Connection Manager (WS)
↓
Chat Gateway
↓
Message Service + Fan-outHTTP for history / auth; WebSocket (or SSE) for live events.
2. Component Design
ChatApp
├── ConversationList
├── ChatThread
│ ├── MessageList (virtualized)
│ ├── TypingIndicator
│ └── Composer
└── ConnectionBanner3. Connection Lifecycle
Connect WS
↓
Authenticate
↓
Subscribe to inbox / rooms
↓
Receive events
↓
On drop → backoff reconnect
↓
Resume from last event / cursorShow a clear connection state in the UI (online / reconnecting / offline).
4. Send Path
User sends
↓
Optimistic local message (clientId)
↓
WS send / HTTP fallback
↓
Ack with serverId + timestamp
↓
Reconcile local → server message5. Ordering & Duplicates
Msg A (t=1) ──→
Msg B (t=2) ──→ (B arrives first)Use:
- Server timestamp / sequence per room
- Idempotent upsert by
clientId/serverId - Sort key in the store, not arrival order alone
6. Offline & Reconnect
- Queue outbound messages while offline
- On reconnect: flush queue, then sync gap (
since=cursor) - Deduplicate events already applied
7. Presence & Typing
- Ephemeral events; throttle typing sends (~1–2s)
- Expire typing locally with a timeout
- Presence via heartbeat or last-seen channel
8. Performance & Scale
Client: virtualize long threads · paginate history · debounce typing · batch receipts.
Backend path:
Clients
↓
WS Gateway (sticky / room routing)
↓
Chat Service
↓
Pub/Sub + Message StoreKey Decisions
| Problem | Solution |
|---|---|
| Live delivery | WebSocket (+ HTTP history) |
| Reconnect storms | Exponential backoff + jitter |
| Wrong order | Per-room sequence / sort key |
| Duplicate messages | Idempotent ids |
| Offline send | Outbox queue |
| Typing spam | Throttle ephemeral events |
| Huge threads | Virtualization + cursor history |
Interview Q&A
Q1. Why not poll?
Polling adds latency and load. WebSockets push events; keep HTTP for history and fallback.
Q2. How do you resume after disconnect?
Store last applied event cursor; on reconnect request since=cursor and merge idempotently.
Q3. Optimistic send — what if it fails?
Keep message in pending / failed; allow retry; never lose the outbox entry until acked.
Q4. How do read receipts scale?
Aggregate or sample at high fan-out; don’t broadcast every receipt to every member of huge rooms.
Q5. Group chat fan-out?
Gateway + pub/sub. Client still upserts by id so duplicate deliveries are safe.
Q6. Accessibility?
Live region for new messages (carefully), focus management in composer, keyboard navigation in conversation list.
Interviewer Checklist
Transport choice · Ordering · Idempotency · Reconnect · Optimistic send · Presence · Performance · Trade-offs