How does a multi-device messaging app keep messages perfectly synced across all devices?
How does a multi-device messaging app keep messages, read status, and edits perfectly synced across phone/tablet/desktop, resolving conflicts when edits happen simultaneously on different devices?
What the system must do · server-authoritative sync with conflict resolution
Quality constraints for multi-device synchronization at global scale
| Property | Target | Why It Matters / Design Impact |
|---|---|---|
| Sync latency | <1s for real-time push to all devices | Action on one device must appear on others near-instantly to feel like one unified inbox. |
| Catch-up latency | <3s for getDifference on reconnect | Device coming online must sync quickly · users won't wait for stale state to resolve. |
| Consistency | Strong per-user (all devices converge to same state) | Divergent state across devices is the worst UX · messages appearing on one but not another. |
| Throughput | 100B+ updates/day across all users | Every message, read receipt, edit, and delete is an update that must reach all devices. |
| Retention | 7-day update log per user | Older than 7 days = force full re-sync. Keeps storage bounded while covering typical offline gaps. |
| Conflict resolution | Last-write-wins with server timestamp | Simple, deterministic resolution. Server is authoritative · no client-side merge logic needed. |
| Multi-device | Support 3-5 concurrent devices per user | Phone + tablet + desktop is the common case. Each maintains independent cursor. |
Deriving infrastructure requirements from device count and update volume
| Step | Calculation | Result |
|---|---|---|
| 1 | 700M MAU · 3 devices avg | 2.1B device sessions |
| 2 | 100B msgs/day → each msg = 1 update · 3 devices | 300B update deliveries/day |
| 3 | 300B · 86400 | ~3.5M update pushes/sec |
| 4 | Update log storage: 700M users · 7 days · 50 updates/day · 200B | ~49TB |
| 5 | getDifference calls: 700M users · 5 reconnects/day · 86400 | ~40K calls/sec |
| 6 | Conflict rate: simultaneous edit on 2 devices | <0.01% of edits (rare) |
Server as source of truth · each device maintains a pts (update sequence) and uses getDifference to catch up
Server-authoritative model simplifies sync · unlike WhatsApp's phone-primary approach
| Decision | Choice | Why | Alternative Rejected |
|---|---|---|---|
| Authority Model | Server as source of truth | All devices are equal peers. Server holds canonical state. Any device can send/edit. No "primary device" concept. | Phone-primary (WhatsApp): desktop depends on phone being online. Terrible UX for multi-device. |
| Sync Protocol | pts sequence + getDifference | Each user has a monotonic update counter (pts). Device sends last known pts → server returns all updates since. Efficient delta sync. | Full state sync: transfer entire inbox on reconnect · O(messages) instead of O(missed updates). |
| Conflict Resolution | Last-Write-Wins (server timestamp) | Simple, deterministic. For chat edits, conflicts are rare and LWW is acceptable. Server assigns authoritative timestamp. | CRDT/OT: overkill for chat messages (not collaborative editing). User-prompt: bad UX for background sync. |
| Update Retention | 7-day update log per user | If device offline >7 days, force full re-sync. Keeps update log bounded. Most devices sync within hours. | Infinite retention: unbounded storage growth. 24h: too aggressive for vacation scenarios. |
| Real-time Push | Persistent connection per device | Each device maintains its own WebSocket/TCP connection. Server pushes updates to all active sessions simultaneously. | Polling: adds latency, wastes bandwidth. Single connection: can't push to multiple devices. |
Multi-device sync must handle network partitions, clock skew, and long offline periods gracefully
| # | Failure / Edge Case | What Breaks | How It's Handled |
|---|---|---|---|
| 1 | Device offline for 8+ days | Update log expired · can't getDifference | Server returns "too old" error. Client performs full re-sync: fetch recent conversations, messages paginated from server. |
| 2 | Simultaneous edit on 2 devices | Both devices think their edit is the latest | Server applies LWW (last timestamp wins). Losing device receives the winning edit as a new update. UI shows final state. |
| 3 | Network partition during sync | Device receives partial update batch | getDifference is idempotent · client retries with same pts. Server returns same updates. No partial application. |
| 4 | Read on phone, desktop shows unread | Read status not synced yet | Read marker is an update with its own pts. Propagates to all devices within 1s. Desktop clears unread badge on receiving update. |
| 5 | Delete message on one device | Other devices still show the message | Delete is an update event (pts incremented). All devices receive "delete msg_id" update and remove from local store. |
Optimized for consistent ordering and efficient delta sync
| Component | Technology | Why This | Why Not X |
|---|---|---|---|
| Update Log | Cassandra (per-user partition) | Append-only log of updates per user. Partition key = user_id. Ordered by pts. Fast range queries for getDifference. | MySQL: write bottleneck at scale. Kafka: not queryable by arbitrary offset range per user. |
| Sequence Generator | Redis INCR (per-user key) | Atomic increment for pts. O(1), sub-ms. Each user has independent counter · no global bottleneck. | DB auto-increment: too slow for real-time. Snowflake IDs: not monotonic per user. |
| Real-time Push | Persistent TCP/WebSocket per device | Server pushes updates to all active sessions. Each device has independent connection. Multiplexed protocol. | Polling: adds 1-5s latency. Push notifications: not real-time enough for active sessions. |
| Conflict Resolution | Server-side LWW (timestamp) | Simple, deterministic. Server clock is authoritative. No client clock dependency. | Vector clocks: more complex, marginal benefit for chat (edits are rare). CRDTs: overkill. |
| Session Registry | Redis (user → active sessions) | Track which devices are online for push routing. TTL-based cleanup on disconnect. | In-memory on gateway: not shared across gateway instances. |
The 5 things an interviewer wants to hear about multi-device sync