← Back to Blog
πŸ—οΈ
System Design

System Design Interview: Design a Real-Time Chat App Like WhatsApp

Step-by-step system design walkthrough for a WhatsApp-scale chat application β€” covering WebSockets, message queues, database sharding, and CDN strategy. Essential for senior engineer interviews.

P

PrepHit Team

System Design Coach

Β·28 August 2026Β·5 min read
#system design#interview#whatsapp#websockets#distributed systems

System design interviews are the gatekeeping round for senior software engineering roles. "Design a chat application" is asked at Google, Meta, Amazon, Swiggy, and Razorpay. This guide gives you a production-grade answer in 45 minutes.

🎯 Interview Framework: How to Structure Your Answer

Follow this 45-minute framework in every system design interview:

1. Clarify Requirements (5 min)
Estimate Scale (5 min)
High-Level Design (10 min)
Deep Dive on Components (15 min)
Handle Edge Cases (5 min)
Discuss Trade-offs (5 min)

Step 1: Clarify Requirements (5 min)

Always ask β€” never assume. For a chat app, key questions:

Functional Requirements:
  • 1-1 messaging? Group chats? (max group size?)
  • Text only, or media (images, voice, video)?
  • Message delivery receipts (sent βœ“, delivered βœ“βœ“, read πŸ”΅)?
  • Online presence (last seen)?
  • Push notifications for offline users?
  • Non-Functional Requirements:
  • How many daily active users?
  • Message latency? (< 100ms for 1-1 chat)
  • Data retention? (messages stored for how long?)
  • Availability vs. Consistency trade-off?
  • For this design: WhatsApp-scale
  • 2 billion users, 100 million daily actives
  • 1-1 and group chats (max 1000 members)
  • Text + media (images, voice)
  • Real-time delivery receipts
  • 7-day message retention on server (E2E encrypted)

  • Step 2: Estimate Scale (5 min)

    Users: 100M DAU
    Messages: 40 messages/user/day = 4 Billion messages/day
    Read:Write ratio = 1:1 (each message read by ~1 person on avg)
    

    QPS (peak): 4B / (86,400s Γ— 0.2 peak factor) = ~230,000 msg/sec

      Storage:
    • Avg message: 1 KB (text) β†’ 4 TB/day (text only)
    • With media (50% users send 1 image/day):
    • 50M Γ— 100KB = 5 TB/day images
    • Total: ~10 TB/day β†’ 3.6 PB/year

    Connections: 100M concurrent WebSocket connections


    Step 3: High-Level Architecture

    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
    β”‚                        CLIENTS                             β”‚
    β”‚  Mobile (iOS/Android)    Web Browser    Desktop App        β”‚
    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                 β”‚
                         Load Balancer (L7)
                                 β”‚
              β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
              β”‚                  β”‚                  β”‚
       β”Œβ”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”   β”Œβ”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”   β”Œβ”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”
       β”‚  Chat Server β”‚   β”‚  Chat Server β”‚   β”‚  Chat Server β”‚
       β”‚  (WS + HTTP)β”‚   β”‚  (WS + HTTP)β”‚   β”‚  (WS + HTTP)β”‚
       β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜   β””β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜   β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜
              β”‚                  β”‚                  β”‚
              β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                 β”‚
                        Message Broker (Kafka)
                                 β”‚
              β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
              β”‚                  β”‚                  β”‚
       β”Œβ”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”   β”Œβ”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”   β”Œβ”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”
       β”‚  Message DB β”‚   β”‚  Presence DB β”‚   β”‚  Media Store β”‚
       β”‚  (Cassandra)β”‚   β”‚    (Redis)   β”‚   β”‚  (S3/CDN)   β”‚
       β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

    Step 4: Deep Dive β€” Key Components

    4.1 Real-Time Messaging: WebSockets vs. Long Polling vs. SSE

    For real-time bidirectional communication, WebSockets win:

    ProtocolDirectionLatencyOverhead
    WebSocketBidirectional~20msLow (after handshake)
    Long PollingServer β†’ Client~200msHigh (repeated HTTP)
    SSEServer β†’ Client only~50msMedium
    Client ──── HTTP Upgrade ────→ WebSocket Server
    Client ←──── ACK ────────────── WebSocket Server
    Client ←──── Message Frame ───── WebSocket Server
    Client ──── Message Frame ────→ WebSocket Server
    Challenge at scale: 100M concurrent WebSocket connections. Each connection holds ~2MB memory β†’ 200 TB RAM needed if single-server. Solution: Connection Routing via Consistent Hashing.

    Each user's WebSocket is maintained by a specific Chat Server. The Presence Service (Redis) maintains a {userId β†’ chatServerId} mapping. When Server A wants to send a message to a user on Server B, it routes through Kafka.


    4.2 Message Flow: Alice Sends to Bob

    1. Alice's app sends message over WebSocket to Chat Server A
    Chat Server A:
       a. Persists message to Cassandra (async)
       b. Publishes to Kafka topic: user-bob-inbox
       c. Sends ack back to Alice (βœ“ sent)
       
    Kafka delivers to Chat Server B (where Bob's WS lives)
    Chat Server B:
       a. Pushes message to Bob over WebSocket
       b. Bob's app sends delivery receipt (βœ“βœ“ delivered)
       
    If Bob is offline:
       a. Kafka holds message (retention: 7 days)
       b. Push Notification Service (FCM/APNs) wakes Bob's device

    4.3 Database: Why Cassandra for Messages?

      Messages have specific access patterns:
    • Write-heavy: Billions of writes/day
    • Read pattern: Always by conversation: "get last N messages for conversation X"
    • No complex joins: Chat apps don't do SQL JOINs
    • Horizontal scalability: Must scale beyond single machine
    Cassandra schema:
    messagesbyconversation (
      conversation_id UUID,  // Partition key
      message_id     TIMEUUID,  // Clustering key (time-ordered)
      sender_id      UUID,
      content        TEXT,
      message_type   TEXT,
      status         TEXT,
      created_at     TIMESTAMP,
      PRIMARY KEY ((conversationid), messageid)
    ) WITH CLUSTERING ORDER BY (message_id DESC);

    This design ensures all messages for a conversation are co-located on the same Cassandra node β€” giving O(1) reads.


    4.4 Media Storage: Images, Voice, Video

      Never store media in your chat database. Use:
    1. S3 (or GCS) for durable object storage
    2. CloudFront / Cloudflare CDN for global fast delivery
    Flow:
    1. Client requests upload URL β†’ /media/upload-url (pre-signed S3 URL)
    Client uploads directly to S3 (bypasses your servers)
    Client sends message with mediaUrl in payload
    S3 triggers Lambda β†’ generates thumbnail β†’ stores in S3
    CDN caches thumbnail edge-side globally

    4.5 Presence System: Online/Last Seen

    Redis: {userId} β†’ {chatServerId, lastSeen: timestamp}
    TTL: 30 seconds (heartbeat every 10s from client)
  • If Redis has no key β†’ user is offline (TTL expired)
  • lastSeen timestamp extracted when user disconnects

  • Step 5: Edge Cases

    ProblemSolution
    Chat Server crashes mid-messageKafka ensures at-least-once delivery. Client de-duplicates by messageId
    Message ordering in group chatUse Cassandra TIMEUUID as message_id (includes timestamp)
    Spam/abuseRate limit: 100 messages/min per user via Redis token bucket
    E2E EncryptionSignal Protocol (same as WhatsApp). Keys exchanged client-side, server never sees plaintext
    Slow consumersKafka consumer groups; each Chat Server reads its partition independently

    Step 6: Trade-offs to Discuss

    Consistency vs. Availability: > "We choose AP (Availability + Partition Tolerance) over strong consistency. Message ordering is best-effort within a conversation β€” acceptable for chat. We'd use stronger consistency only for financial transactions." Push vs. Pull for offline messages: > "We use Kafka (push) because it scales better than polling. If we used pull, 100M offline users polling every 30s = 3.3M req/s just for empty responses."

    🎯 Practice Makes Perfect

    Record your answer to this question out loud in 45 minutes. You'll be surprised how often you skip important components.

    Want to practice with AI feedback? PrepHit AI's mock interview feature evaluates your system design answers on Clarity, Technical Depth, and Structure β€” just like a real interviewer.

    Ready to Test These Tips?

    Scan your resume against any job description for a free ATS score and skill gap report.

    ✨ Analyze My Resume β€” Free