Figma's Postgres Sharding
Figma delayed sharding for years using replicas and vertical partitioning, then sharded Postgres horizontally without downtime using logical shards and a proxy layer.
The sequence, as published in 2024
The order of operations is the most instructive part, because it is the order most teams skip:
1. Scale up. Larger instances, for as long as that worked. 2. Read replicas. Move read traffic off the primary. 3. Vertical partitioning. Move whole tables into separate databases by domain — the "split by function" step. This bought years and required no application sharding logic. 4. Horizontal sharding. Only when a single table's write volume and size exceeded what one primary could serve.
Each step is cheaper and more reversible than the next. Sharding was the last resort, and by the time they reached it the requirement was precise rather than general.
The design choices worth stealing
Logical shards decoupled from physical instances. Data is assigned to a large fixed number of logical shards; many logical shards are hosted per physical database. Growing the fleet means moving logical shards, not rehashing rows. This makes resharding a routine operation rather than a migration project, and deciding it up front costs nothing.
A proxy layer (DBProxy) rather than application-level routing. Query parsing, shard resolution and routing live in one place. Applications keep issuing something close to ordinary SQL, and the routing logic can be improved without touching every service.
Choosing shard keys per table, aligned to the product's natural partition. Figma's data partitions cleanly by user, file or organisation — which is why most queries stay within one shard. This is the criterion that decides whether sharding is pleasant or painful, and it is a property of the domain rather than of the database.
Restricting what SQL is allowed. Cross-shard joins and unbounded queries were removed or constrained, deliberately, so the sharded system stayed predictable.
The lesson
Sharding is a one-way door, so the value is in postponing it correctly and then doing it with optionality preserved. Vertical partitioning and replicas are not "not real solutions" — they are the correct earlier steps, and skipping to sharding because it sounds like the grown-up answer imports permanent complexity years before it is required.