AlgoInsight

System Design

Database Sharding

When your data outgrows a single machine, sharding is how you spread it across many - each holding a slice. It's the standard way to scale a database's writes and storage horizontally. Here's how it works, and where it gets hard.

By Admin2026-06-1814 min readshardingdatabasescalabilitysystem-designdistributed-systemshorizontal-scaling

There comes a point in a growing system where a single database machine simply can't keep up - either the data is too large to fit, or the write volume is too high for one machine to handle. You can make the machine bigger for a while (vertical scaling), but that has a ceiling. Eventually you have to spread the data across multiple machines. Sharding is the technique for doing exactly that: splitting a database horizontally across many machines, each holding a slice of the data.

Sharding is the standard answer to scaling a database's writes and storage beyond one machine - and it's also one of the more challenging things to get right. This guide explains what sharding is, how data gets split, how queries find the right shard, and the real challenges that make sharding a serious decision rather than a casual one.

What sharding is

Sharding means splitting your data across multiple database machines, where each machine (a shard) holds a subset of the total data. Instead of one database holding all the rows, you have many databases, each holding some of the rows. Together, the shards hold the complete dataset; individually, each holds only its piece.

The key word is horizontal: you're splitting the rows of your data across machines (each shard has the same structure but different rows), not splitting the columns or the features. If you have a billion users, you might put users 1–100 million on shard 1, the next 100 million on shard 2, and so on - same table structure on each shard, different users.

This is fundamentally different from replication. Replication copies the same data to multiple machines (for read scaling and redundancy). Sharding splits different data across machines (for write and storage scaling). Replicas all have everything; shards each have a piece. Real systems often use both - sharding to split the data, and replication within each shard for redundancy.

graph TD
    APP[Application] --> ROUTE[Routing: which shard?]
    ROUTE --> S1[(Shard 1<br/>users 1–100M)]
    ROUTE --> S2[(Shard 2<br/>users 100M–200M)]
    ROUTE --> S3[(Shard 3<br/>users 200M–300M)]
This diagram shows database sharding. The application sends a request to a routing layer, which determines which shard holds the relevant data based on a sharding key. The data is split across three shards: shard 1 holds users 1 to 100 million, shard 2 holds the next 100 million, and shard 3 the next. Each shard has the same table structure but a different subset of the rows.

The shard key: the most important decision

Everything about sharding hinges on the shard key (or partition key) - the piece of data used to decide which shard a given row belongs to. When you store or look up a row, the system uses its shard key to determine which shard it lives on. Choosing the shard key well is the single most important decision in sharding, because it determines how evenly data and load spread across shards, and how efficiently queries run.

A good shard key spreads data and load evenly across shards (no single shard overwhelmed while others sit idle) and aligns with how you query the data (so common queries hit a single shard rather than all of them). A poor shard key creates hot spots (one shard taking most of the load) or forces queries to hit every shard. We'll return to why this is so consequential.

How data is split: sharding strategies

There are several strategies for mapping rows to shards, each with trade-offs:

The choice depends on your access patterns. Hash-based sharding is a common default because it distributes evenly; range-based suits range-query-heavy workloads; directory-based offers flexibility at the cost of the lookup layer.

Routing: finding the right shard

Once data is sharded, every query needs to reach the right shard. This routing - determining which shard holds the data for a given key - happens through a routing layer (which could be logic in the application, a separate routing service, or a feature of the database). When a query comes in with a shard key, the router applies the sharding strategy (compute the hash, check the range, consult the directory) to find the shard, and sends the query there.

The cleanest case is a query that includes the shard key - it routes straight to one shard, efficiently. The problematic case is a query that doesn't include the shard key (or needs data from multiple shards), which we'll see is one of sharding's main challenges.

The hard parts of sharding

Sharding solves the scale problem but introduces genuine complexity. The challenges that make it a serious decision:

Tip: Emeka's note from production: The shard key is everything, and I cannot overstate how much pain a bad one causes. Choose a key that distributes load evenly and matches your most common queries, so those queries hit a single shard. The classic mistake is sharding by something that creates hot spots - sharding by date when most activity is recent (the newest shard gets hammered while old shards idle), or by a key where a few values dominate. And think hard before you shard at all: it's a one-way door that's costly to undo. I've seen teams shard prematurely, taking on all this complexity for scale they hadn't reached, when a bigger single machine plus caching and read replicas would have carried them for years. Shard when you genuinely must - when one machine truly can't hold the data or handle the writes - not before.

A worked example: choosing a shard key

Let me make shard-key choice concrete, because it's where sharding succeeds or fails. Suppose you're sharding the database for a large messaging app, and the dominant query is "get all messages for a given conversation." What should the shard key be?

A tempting choice is the message's own ID or timestamp - but that's a trap. Sharding by timestamp means all recent messages land on the newest shard, so that one shard takes nearly all the write traffic while older shards sit idle: a classic hot spot. Sharding by message ID scatters a single conversation's messages across every shard, so the dominant query ("all messages in this conversation") has to hit every shard and merge results - slow and expensive.

The better choice is to shard by conversation ID. Now all messages for a conversation live on the same shard, so the dominant query routes to a single shard - fast and clean. And because conversations are spread across many users, the load distributes reasonably evenly, as long as no one conversation is absurdly larger than the rest. The shard key aligns with the access pattern and distributes load - exactly what a good shard key does.

Notice the reasoning: look at your dominant query, choose a key that keeps that query on one shard, and check that the key distributes load evenly. Get both right and sharding works; get either wrong and you have hot spots or scatter-gather queries. This is why I say the shard key is the whole ballgame.

Handling cross-shard queries in practice

Even with a good shard key, some queries will need data from multiple shards - and how you handle them matters:

The throughline: sharding optimizes for queries that align with the shard key, and you architect around the queries that don't.

Resharding and consistent hashing

One of sharding's hardest operational problems is resharding - redistributing data when you add or remove shards as the system grows. A naive scheme makes this brutal: if you assign rows to shards by "hash modulo number-of-shards," then adding one shard changes the modulo, which remaps almost every key to a different shard, forcing a massive data migration.

The technique that tames this is consistent hashing, which assigns keys to shards so that, when you add or remove a shard, only a small fraction of keys need to move (rather than nearly all of them). This makes growing the cluster far less painful. Consistent hashing is a foundational technique for exactly this reason - it's what lets a sharded or distributed system add and remove nodes without reshuffling everything. (See the dedicated guide on consistent hashing for how it achieves this.) Knowing that naive hash-modulo sharding makes resharding catastrophic, and that consistent hashing is the fix, is one of the real operational realities of running sharded systems.

Sharding and replication together

A final clarification, because the two are easily conflated: sharding and replication solve different problems and are typically used together. Sharding splits the data across machines to scale writes and storage; replication copies data for redundancy and read scaling. In a real production setup, you shard the data across many shards, and each shard is itself replicated (a primary with replicas) so that no shard is a single point of failure and each shard's reads can be spread across its replicas. So a large sharded database is often a grid: many shards (for scale) each with several replicas (for reliability and read scaling). You don't choose between sharding and replication - you combine them.

When to shard (and when not to)

Sharding is powerful but costly in complexity, so the decision matters:

Shard when a single database machine genuinely can't handle your data size or write volume, even after vertical scaling, caching, and read replicas. That's the real trigger: you've exhausted the simpler options and the write/storage load truly exceeds one machine.

Don't shard when simpler approaches still have headroom. Read replicas handle read scaling; caching relieves read load; a bigger machine handles a lot. Because sharding adds so much complexity and is hard to undo, it should be a later resort, not a first move. The order is usually: optimize and cache, scale up the machine, add read replicas, and only then, when writes or storage genuinely exceed one machine, shard.

Interview: In a system design interview, sharding is the answer for scaling writes or storage beyond one machine - but the strong signal is when and how you propose it. Reaching for sharding immediately, before simpler scaling, is a flag; proposing it as the answer to a genuine single-machine limit, with a well-reasoned shard key that distributes load and matches the query pattern, is a strong signal. Mentioning the hard parts - cross-shard queries, hot spots, resharding pain - shows you understand sharding as a serious trade-off, not a free scaling button.

The bottom line

Sharding splits a database horizontally across multiple machines, each holding a subset of the rows, to scale writes and storage beyond what one machine can handle. It hinges on the shard key, which determines how data and load distribute - chosen well (even distribution, aligned with queries) it works beautifully; chosen poorly it creates hot spots and cross-shard queries that hit every machine. Strategies (range, hash, directory, geographic) map rows to shards differently, and the hard parts - cross-shard queries and joins, hot spots, resharding, operational complexity - make sharding a serious decision.

Shard when you genuinely must, choose the shard key with care, and reach for the simpler scaling options first. For how sharding relates to the broader term partitioning, see the companion piece. We cover scaling the data layer across System Design Fundamentals.


Go deeper

More articles