How Slack Works: Workspace-Sharded Architecture at Scale

A look at how Slack works. Slack runs tens of millions of concurrent workspaces on a stack that started as a single PHP/Hack service and evolved into one of the cleanest sharded-by-workspace architectures on the internet. The non-obvious bet they made early: treat the workspace as the atomic unit of state. Every connection, every channel, every search query stays inside one workspace’s blast radius. That decision is why Slack scales.

How Slack works: architecture diagram showing edge routing to channel servers sharded by workspace with Vitess MySQL storage and Redis presence cache

How Slack Works: The problem at scale

Slack’s challenge isn’t message throughput per second. It’s fanout. When someone types in #general at a 50,000-person company, every connected device in that workspace needs to receive the keystroke within ~200ms for typing indicators to feel live, and the message itself within a second. Across millions of workspaces with anywhere from 5 to 500,000 members each, the system has to hold ~10 million concurrent WebSockets, route messages only inside the right workspace, never leak data between workspaces, and survive any single component failing without dropping a connection.

The constraint that produced the architecture: workspace isolation must be physical (separate shard), not just logical (separate row in a shared DB). One workspace’s traffic spike cannot degrade another’s.

The core architecture

The client opens one WebSocket to Slack’s edge tier, a fleet of HAProxy + PHP/Hack servers that authenticate the connection and route API calls. The edge holds no state itself; it forwards to a Channel Server, which is the heart of the system. Each workspace is “owned” by exactly one channel server at any given time, and that server is the source of truth for presence, typing indicators, and message fanout for every member of that workspace. When a member posts a message, the channel server fans it out to every member’s connected device in parallel. Persistence and async work (search indexing, bot invocations, webhook delivery) go through a Kafka queue to downstream workers.

Why workspace-sharding is the whole game

Slack’s primary data store is Vitess, sharded MySQL, originally built at YouTube to scale MySQL beyond one machine. The genius of Slack’s schema is that every table has a workspace_id as its leading column, and Vitess shards by that key. A single workspace’s data (every channel, message, user, file, app) lives on exactly one Vitess shard. Cross-workspace queries don’t exist; you can’t accidentally write a query that joins two workspaces’ data, because the storage layer makes it physically impossible.

This is why Slack survived its early hyper-growth. When a shard got too hot, they moved specific workspaces to a new shard. The blast radius of any storage failure is exactly one workspace. There’s no global join to lock up. A 50,000-person company’s #general thread doesn’t share a database with a competitor’s #general thread.

The channel server is the bottleneck and the win

Channel servers are stateful in-memory processes: they hold the active presence set and routing tables for the workspaces assigned to them. Slack’s engineering blog is unusually honest about the trade-off: stateful servers are harder to operate than stateless ones (you can’t just kill a process; you have to drain its workspaces first), but the latency win is enormous. Going to Redis for every typing-indicator broadcast would double the latency, and going to the database would ten-x it. In-process fanout is what makes typing feel live.

When a channel server fails, its workspaces fail over to a standby that already has the state mirrored. This is the most operationally complex part of Slack’s stack. They’ve written extensively about the migration tools they had to build to make workspace moves safe.

The one non-obvious insight

Slack’s PHP/Hack legacy at the edge is not a tech-debt apology. It’s a deliberate choice. Early Slack bet on Hack (Facebook’s typed PHP) for the edge because the team knew it, the deploy story was simple, and the edge does no heavy compute. Channel servers in a different language could have been rewritten twice by now; the edge didn’t need to be. Engineers often default to “rewrite in Go/Rust,” but Slack’s edge proves the lesson: only rewrite the part that’s actually the bottleneck. The edge isn’t.

Slack is the case study for sharding by the right domain primitive. Workspace-level isolation bought them hyper-growth without rearchitecture, let them survive failures at workspace granularity, and kept cross-tenant queries physically impossible. The pattern every multi-tenant SaaS should study.