Skip to content
Devgo

Discord

Realtime chat with Elixir and a hybrid DB/NoSQL backend

Discord serves real-time guild chat with Elixir/OTP (millions of concurrent connections), ScyllaDB for message history, and for presence/sessions. Messages fan out to online members via persistent connections; history is queried from ScyllaDB.

Product constraints

  • Millions of concurrent connections; low-latency message delivery.
  • Message history must be queryable and durable at huge scale.
  • Presence and typing indicators are high-frequency, ephemeral.
  • Guilds (servers) can have huge member counts; fan-out is large.

High-level diagram

Discord architectureA block diagram of the Discord system's main components and request flow.ClientElixir gatewayRedis pub/subScyllaDBby channelOnline membersHistory reads
Illustrative block diagram of Discord. Not to scale; see the request path below for flow.

Request path

  1. Send message. Client sends over a persistent connection (Elixir/OTP gateway); the message is persisted to ScyllaDB.
  2. Fan-out. The gateway fans the message to all online members' connections across nodes (inter-node via /pub-sub).
  3. Presence. Presence and typing state kept in , ephemeral and high-frequency.
  4. History. Offline/later reads query ScyllaDB by channel id, ordered by message id (time-based).

Data model

Messages in ScyllaDB partitioned by channel id, clustered by message id (time-ordered). Guilds/channels/members in a mix of DBs. Presence, sessions, and ephemeral state in .

Storage / cache / queue choices

Storage

ScyllaDB (-compatible) for message history, partitioned by channel.

Cache

for presence, sessions, typing, and fan-out.

Queue

Elixir/OTP process messaging + for cross-node fan-out.

Scaling levers

  • Elixir/OTP lightweight processes handle millions of connections per node.
  • ScyllaDB partitions by channel for write throughput and channel-scoped reads.
  • for cross-node fan-out to online members.
  • Separate ephemeral (presence, ) from durable (messages, ScyllaDB) state.

Copy vs skip (for a smaller team)

Copy
  • Partition message history by channel (chat id) for write scale.
  • Use a connection-optimized runtime (Elixir/OTP or similar) for fan-out.
  • Keep ephemeral state (presence) in a cache, not the DB.
  • Pub/sub for cross-node fan-out to online members.
Skip
  • Storing presence/typing in the DB (ephemeral — use a cache).
  • Elixir specifically without expertise (use any actor/connection model).
  • Single-node fan-out (shard by guild).

, , , ,

Sources