Database sharding
Distributing a database's data and writes across multiple primary servers — rather than only adding read replicas — so the whole fleet acts as one logical database. Sharding is the distributed end of the operational-databases spectrum, and planetscale-768-servers is the founding source: 256 shards × 3 servers = 768 machines, ~4 TB each, presented as a single database.
Why replicas aren't enough
planetscale-768-servers frames three bottlenecks that read replicas can't fix, which is what forces sharding:
- The single-writer WAL — every write still funnels through one primary's write-ahead log, so adding read replicas does nothing for write throughput.
- Replicas duplicate, they don't distribute — every replica holds the whole dataset, so capacity doesn't grow by adding them.
- Monolithic backups — backing up one enormous database to object storage can take days.
Sharding attacks all three by splitting the data itself across many primaries.
The abstraction — making N servers look like 1
The trick is a proxy router that hides the fan-out from the application:
- Parse the incoming SQL and consult topology metadata (often JSON) describing where data lives.
- Route each query to the right shard by a sharding key — commonly a hash of a column
(e.g.
user.id), which spreads rows evenly. - Aggregate results from multi-shard queries back into one answer; pool and buffer connections.
This bullet hides the expensive part. Any query the shard key can't route — an
ORDER BYacross all rows, aCOUNT(*), a deepLIMIT/OFFSET— becomes a scatter-gather: every shard runs it, and the router merges. sharded-pagination-interview-post poses the worst ordinary case (page 100,000 of an order table); cross-shard-queries holds the mechanism, from Vitess's own documentation — push down what the vindex can route, fan out and merge at the proxy when it can't. - Sit behind a network load balancer so the application connects to a single hostname
(
mydb.pscale.com) and never sees the 768 servers underneath.
The named routers: Vitess for MySQL and Neki for Postgres, both from planetscale — and since 2026-09-19 this wiki has the second one's architecture rather than only its name. Neki adds a detail the generic account of sharding hides: which engine you shard changes the architecture. Postgres identifies objects by numeric OID and clients cache them off the wire, so independent shards would disagree about a custom type's identity — which forces one shard in the cluster to be authoritative and translate every other shard's OIDs. MySQL has no equivalent to reconcile. A router is not engine-agnostic infrastructure with a driver swapped in. This proxy-router layer is the operational counterpart to a single-node engine like turso — where Turso collapses the database into the process, sharding explodes it across a fleet while keeping the same one-database interface.
The other place the router can live (added 2026-08-20)
A proxy is not the only home for the routing logic. citus puts it inside every Postgres server as an extension: a coordinator node holds the shard metadata and rewrites each statement into plain SQL against shard tables, which are themselves ordinary Postgres tables on the workers. The architectural difference is not cosmetic — a proxy has to reimplement whatever the engine can do (that is what a vindex, a VSchema and a plan-merger are), while an in-engine router inherits the engine's planner, index types and extensions for free. Citus's own argument for the design is that PostGIS, JSONB, lateral joins and time partitioning keep working on a distributed table.
The price is symmetrical. The proxy is engine-agnostic and can front instances it does not run inside; the extension is welded to one engine and one major-version cadence, which is why citus maintains three release branches at once against different Postgres versions.
Two ways to pick the shard (added 2026-08-20)
Everything above is row-based sharding: hash a column, place the row. citus ships a second
model since its 12.0 release, schema-based sharding, where a whole database schema is the unit and
routing follows the connection's search_path. A multi-tenant app gets a schema per tenant and needs
no query changes at all; a microservice connects as a user whose default search_path is its own
schema and needs no changes either.
The trade is granularity against intrusiveness. Row-based sharding requires a distribution column present in your data model and rewards you with even spread and per-row placement; schema-based sharding requires only that tenants already be separated, and moves data a whole schema at a time. Citus frames the second as the option for applications "that cannot undergo the changes required to onboard row-based sharding" — which is a statement about migrations, not about throughput.
Making several tables work together
Sharding one table is the easy half. The queries an application actually runs join tables, and shard-colocation is the mechanism that keeps those joins local: give two tables the same distribution column and matching values land on the same node, so joins, foreign keys and transactions scoped to one key never leave it. What co-location does not cover is exactly what cross-shard-queries costs out.
Related
operational-databases · online-transaction-processing · planetscale-768-servers · sharded-pagination-interview-post · cross-shard-queries · shard-colocation · vitess · citus · planetscale · turso · synthesis