Case study boundary
Use this as a learning model.
This page explains architectural patterns and constraints inspired by Discord. It should not be read as the exact private production architecture or as a one-size-fits-all recommendation.
Evidence
Public info + inference
Learn first
Concepts behind this architecture
WebSocket
Keep a bidirectional connection open for low-latency client and server messages.
Pub/Sub
Broadcast events from publishers to many independent subscribers.
Backpressure
Slow producers down when consumers cannot keep up.
Sharding
Split a dataset across machines so storage and traffic can scale horizontally.
Overview
Discord is a communication platform originally built for gaming communities, now serving 200M+ monthly active users across diverse interest groups. Its architecture is uniquely optimized for low-latency voice chat alongside text messaging, supporting millions of concurrent voice connections. Discord pioneered guild-based sharding, built its real-time infrastructure on Elixir/Erlang, and migrated its message storage from MongoDB to ScyllaDB to handle trillions of messages. The platform’s bot ecosystem and rich presence system are integral architectural components.
Scale
200M+
Monthly active users
10M+
Concurrent voice connections
4B+
Messages per day
19M+ active
Servers (guilds)
Requirements
Functional
- Guild-based text channels with categories
- Low-latency voice and video channels
- Screen sharing and Go Live streaming
- Rich presence and activity status
- Bot framework and application commands
- Role-based permissions at guild, category, and channel level
- Direct messages and group DMs
Non-Functional
- Ultra-low voice latency (<50ms codec-to-ear)
- High availability for voice infrastructure
- Horizontal scaling to millions of concurrent guilds
- Sub-second message delivery globally
- Support for guilds with 1M+ members
- Efficient storage for trillions of messages
High-Level Architecture
Key Components
WebSocket Gateway
Maintains persistent WebSocket connections for every online user. Built in Elixir for massive concurrency — each gateway node handles hundreds of thousands of connections. Events (messages, presence updates, typing indicators) are pushed to clients in real time.
Guild Service
Manages guild metadata, channels, roles, and permissions. Guilds are the primary sharding unit. Large guilds (100K+ members) use lazy member loading — the full member list is only fetched on demand.
Message Service
Handles message CRUD, attachments, embeds, and reactions. Messages are stored in ScyllaDB, partitioned by channel_id with a clustering key on message timestamp (Snowflake IDs) for efficient range queries.
Voice Service
Manages voice state, channel assignments, and coordinates with SFU (Selective Forwarding Unit) servers. Each voice channel runs on a dedicated SFU that selectively forwards audio/video streams to participants without transcoding.
SFU Servers
Selective Forwarding Units handle real-time media routing. Each SFU receives audio/video from participants and selectively forwards streams based on who is speaking (voice activity detection) and client bandwidth. Uses Opus codec for audio.
Presence Service
Tracks online/idle/DND/invisible status plus rich presence (currently playing, listening to Spotify, etc.). Backed by Redis Cluster with millions of presence entries updated via heartbeats.
Bot Gateway
Dedicated gateway for bot connections, separate from user gateways. Supports sharded bot connections for bots in thousands of guilds. Processes application commands (slash commands) and interaction events.
Push Service
Delivers mobile push notifications and manages notification settings per-channel, per-guild, and per-user. Batches and deduplicates notifications to avoid notification storms.
Data Model
Guild Sharding and Snowflake IDs
Discord’s core scaling strategy is guild-based sharding. Each guild (server) is assigned to a specific shard, and all operations for that guild are routed to the same set of backend processes.
Snowflake IDs: Discord uses Twitter-style Snowflake IDs — 64-bit integers encoding a timestamp, worker ID, and sequence number. This provides globally unique, time-ordered, and roughly sortable IDs without coordination. Message IDs are Snowflakes, enabling efficient range queries (“fetch messages before this ID”).
Gateway sharding: For large bots, Discord requires bot connections to be sharded — each shard handles events for a subset of guilds. The shard for a guild is determined by (guild_id >> 22) % num_shards.
Large guilds: Guilds with 100K+ members use lazy member loading — the client doesn’t receive the full member list on connect. Instead, members are loaded on-demand as the user scrolls the member sidebar or types @mentions.
MongoDB to ScyllaDB Migration
Discord stored messages in MongoDB for years but hit scaling limits as the platform grew to trillions of messages.
Problems with MongoDB:
- Hot partitions on popular channels caused latency spikes
- Compaction storms during off-peak hours degraded performance
- Memory-mapped storage engine was unpredictable under pressure
Why ScyllaDB?: A C++ rewrite of Cassandra offering better tail latencies and more predictable performance. Its shard-per-core architecture eliminates coordination overhead.
Data model: Messages are partitioned by channel_id with message_id (Snowflake) as the clustering key. This means fetching recent messages in a channel is a single partition scan in reverse order — extremely efficient.
Migration strategy: Discord ran dual-writes to both MongoDB and ScyllaDB, validated consistency, then cut over reads. The migration handled trillions of messages with zero downtime.
Voice Architecture and SFU Design
Discord’s voice is one of its biggest differentiators — it needs to feel instant, like sitting in a room together.
SFU model: Each voice channel is assigned a Selective Forwarding Unit (SFU) server. The SFU receives encoded audio from all participants and selectively forwards each participant’s stream to others. No transcoding happens server-side, keeping latency minimal.
Opus codec: All voice is encoded using Opus at 64kbps (adjustable). Opus provides excellent quality at low bitrates and has near-zero algorithmic delay (~26.5ms).
Voice activity detection: The SFU uses server-side VAD to determine who is speaking. Only active speakers’ audio is forwarded at full rate — silent participants send minimal keep-alive frames.
Region selection: Voice servers are deployed in 15+ regions. When a voice channel is created, the server closest to the majority of participants is selected. Users can override this with a per-channel region setting.
Priority speaker: In large voice channels, admins can enable priority speaker mode, which uses server-side mixing to attenuate other participants’ audio.
Architectural Tradeoffs
Elixir/Erlang for WebSocket gateways
Pros
- +Millions of concurrent connections per node
- +Fault-tolerant process model
- +Hot code upgrades for zero-downtime deploys
Cons
- −Smaller hiring pool than Go or Java
- −Garbage collection pauses at extreme scale
- −Interop overhead with non-BEAM services
ScyllaDB over MongoDB for messages
Pros
- +Predictable tail latencies
- +Linear horizontal scaling
- +Efficient time-series queries via clustering keys
Cons
- −Less flexible query patterns than MongoDB
- −Eventual consistency requires careful modeling
- −Operational complexity of managing a Scylla cluster
SFU over MCU for voice
Pros
- +No server-side transcoding — lower latency
- +Scales linearly with participants
- +Clients control their own decode/render
Cons
- −Client bandwidth scales with participant count
- −Heterogeneous network conditions harder to handle
- −Client must decode multiple streams simultaneously
Learn From Discord
Copy a learning context prompt for an AI assistant. It keeps assumptions visible and asks for tradeoffs, cost drivers, failure modes, and what to measure before adding complexity.