Frontend System Design: Build Discord

“Design Discord” is a senior+ frontend system-design prompt that combines real-time messaging, voice/video, presence at scale, and a large client-side state graph. Discord’s desktop client is famous for being a heavy Electron app; the frontend interview tests whether you can decompose its features into a clean state architecture.

Clarify scope

  • Servers (guilds), channels, DMs?
  • Voice and video channels included?
  • Threads, forum channels, stage channels?
  • Offline / cached state?
  • Cross-platform (desktop + mobile parity) or web only?

The state graph

Discord’s state is large; the most-cited Discord engineering post described moving from Redux-of-everything to a more scoped store. The shape:

  • guildsById — Map of all servers the user is in
  • channelsById — Map of channels (across all guilds and DMs)
  • messagesByChannel — Map of channel ID → (message list, cursor)
  • membersByGuild — guild members (often huge)
  • presenceByUserId — online state, custom status
  • voiceStates — who is in which voice channel, mute, deafen
  • readState — last-read message per channel

Memory matters

A user in 100 servers with 50 channels each can have data for 5,000 channels in memory. Strategies:

  • Lazy-load message history per channel; do not preload all
  • Drop messages from inactive channels under memory pressure
  • Member lists for very large guilds (100K+) are virtualized and lazily fetched
  • Discord historically stored a large in-memory cache; modern variants page to disk via IndexedDB

WebSocket gateway

  • Single persistent connection per client
  • Receives all events: messages, presence, typing, voice state, member joins
  • Sharded server-side; client is unaware
  • Heartbeat every 41 seconds (Discord-specific); reconnect with sequence number on disconnect
  • Resume protocol replays missed events

Voice and video

  • WebRTC for media; Discord runs custom SFU servers
  • Voice channel join: signaling over the gateway, then RTP to the SFU
  • Video and screen share are layered on the same SFU
  • Krisp-style noise suppression in the client (CPU)
  • Voice activity indicator updates every ~30ms during talking

Channel switching

Snappy channel switch is a Discord differentiator:

  • Pre-fetched recent messages for the most-recently-used channels
  • Rendered placeholder while paginating older messages
  • Compose box state preserved per channel (drafts)
  • Typing-indicator state preserved (do not flash)

Message rendering

  • Virtualized list — only visible messages mounted
  • Variable-height messages (text, image, embed, code block)
  • Markdown rendering with custom Discord syntax (mentions, channel links, custom emoji)
  • Edit / delete updates by message ID; tombstones for deletes
  • Reactions update the reaction map without re-rendering the message body

Presence at scale

  • Discord delivers presence for the visible member list, not all members
  • Subscribe to presence updates for the displayed members; unsubscribe when scrolled away
  • For very large guilds, presence is fanned out via lazy queries

Notifications and unread state

  • Per-channel last-read message ID, persisted on the server
  • Mention bumps a separate counter
  • Per-guild “any unread” derives from channel unread states
  • Sidebar shows unread bubbles; navigation marks-as-read

Threads and forum channels

  • Thread = child channel of a parent channel
  • Auto-archive after inactivity
  • Forum channel = root with many threads, no top-level chat
  • State stored in same channel/message maps with a parent link

The Electron / web split

  • Discord desktop is Electron — same codebase as web with native integrations
  • Native: push-to-talk hotkey (global), system overlay, autostart
  • Web: subset; voice still works, push-to-talk limited
  • Mobile: separate React Native codebase

Offline behavior

  • Cached message store in IndexedDB for recently-active channels
  • Queued send: messages composed offline are sent on reconnect
  • “Reconnecting…” banner; messages sent during disconnect remain optimistic until confirmed

Performance considerations

  • The Discord engineering post about reducing CPU on the message list is a classic; rendering tens of messages efficiently matters
  • Memoize messages by ID
  • Avoid context that re-renders entire trees on small updates
  • Profile with React DevTools; focus on the most-mounted components

What separates senior from staff

Senior candidates draw the state shape and discuss virtualization. Staff candidates address memory pressure across thousands of channels, the WebSocket reconnect/resume protocol, and the lazy-presence subscription model. Principal candidates raise the cross-platform architecture (web/desktop/mobile) and the platform-specific tradeoffs.

Frequently Asked Questions

How does Discord handle a guild of 1M members?

Member list is lazy and chunked; full member fetch is rate-limited. Presence subscriptions are scoped to the visible window. The client never has 1M members in memory at once.

What about end-to-end encryption?

Discord does not E2E-encrypt by default (server-readable for moderation). Voice DM E2E encryption was added recently. If asked about E2E DM design, see the Signal-style mobile system design question.

Why is the desktop app heavy?

Electron + the size of state + voice processing. There is no fundamental fix; the team has reduced memory and CPU significantly over the years but the architecture has costs.

Scroll to Top