Notion sharded its Postgres estate into 480 logical shards in 2021 and in 2023 moved those shards onto a larger number of physical machines. A team that shards into 32 databases and later needs 96 faces a far harder job. What did the 2021 decision buy and what does it cost to maintain?
Show the full answer Hide the answer
The situation they were in
A single Postgres instance under a workload growing faster than a machine could. The obvious move is to split data across N databases by a key. The trap is that N becomes part of the routing logic, usually as a hash modulo N, and every future change to N moves most of the rows.
What they chose
A layer of indirection: route to a logical shard, then map logical shards to physical hosts. With 480 logical shards over a smaller number of machines, each host owns many logical shards. Growing the estate means moving whole logical shards between hosts, which is a replicate-and-cut-over operation per shard, not a rehash of the dataset. Notion described doing exactly this in 2021 and then redistributing onto more physical hosts in 2023.
Why it fit their constraints
The workspace is a natural partition key: nearly every query is scoped to one workspace, so cross-shard queries are rare rather than pervasive. Sharding works when the access pattern already has a boundary in it, and fails when queries routinely span keys.
The number 480 is chosen for arithmetic, not for load. It has many divisors, so the estate can be 8, 12, 16, 24 or 32 machines with logical shards divided evenly each time. Pick a highly composite logical shard count and the physical topology becomes a scheduling decision rather than a migration.
What it cost them
- Every query must carry the partition key. Application code, background jobs and analytics all have to route, and anything that cannot is either a fan-out or lives elsewhere.
- Cross-shard transactions are gone. Operations spanning workspaces become sagas or asynchronous reconciliation.
- 480 shards is 480 of everything: connections, schema migrations, vacuum schedules, monitoring series. Schema changes need tooling to apply everywhere and to be resumable.
- Analytics had to move off the transactional estate, because a query across all workspaces is exactly what the design makes expensive. Notion has described building a data lake with change data capture for this reason.
Where copying it would be a mistake
A single Postgres instance goes much further than most teams believe, and sharding is close to irreversible. The honest sequence is: fix the queries, add an index, add read replicas for read load, partition the largest tables within one instance, move cold data out, then move to a bigger machine. Sharding is justified when write throughput or working-set size exceeds one machine, not when read load does - replicas fix reads and cost a fraction of the complexity.
The part worth copying at any size is cheap: if you do shard, shard into far more logical shards than you have machines, and choose a count with many divisors. That decision costs nothing on day one and is the difference between a weekend of shard moves and a quarter-long migration.
When not to shard at all
If the workload has no natural partition key - queries routinely span whatever you would shard by - then no shard count saves you, and the right answer is a distributed database that handles it, a different data model, or accepting the fan-out with its tail latency.