> ## Documentation Index
> Fetch the complete documentation index at: https://notes.kodekloud.com/llms.txt
> Use this file to discover all available pages before exploring further.

# How Real Databases Shard for You

> Explains how production databases implement sharding, comparing relational sharding layers and NoSQL built-in distribution, routing and resharding, shard key selection, and operational tradeoffs.

In this lesson we explain how production databases handle sharding for you, how to pick the right system, and when you should shard at all. We cover two broad families (relational vs NoSQL), show how common systems perform routing and resharding, and give guidelines for selecting a shard key.

Why this matters: sharding affects query performance, operational complexity, and whether joins and cross-shard transactions are practical. Understanding each system’s sharding model helps you design the right data model and choose where to optimize: at the database layer, the application, or via caching.

## Two database families: Relational vs NoSQL

Relational databases (MySQL, Postgres) store data in tables with fixed columns and explicit relationships (for example: Users, Chirps, Likes). They excel at joins and strict correctness guarantees and are queried with SQL:

```sql theme={null}
SELECT name, id
FROM users
JOIN chirps USING (user_id);
```

Relational systems are typically built around a single primary machine by default and do not split a single table across machines without an additional layer that handles splitting and routing.

NoSQL databases (Cassandra, DynamoDB, MongoDB) were designed from the start to distribute data across many machines. To achieve horizontal scale they commonly relax cross-shard joins or strict transactional guarantees (or provide them only in limited or slower ways), because enforcing those guarantees across machines requires cross-network coordination. The key practical difference: relational databases usually rely on an external sharding layer, while many NoSQL systems have distribution built in.

Example of normalized relational rows (for clarity):

```text theme={null}
USERS
USER_ID NAME
41      Chris
18      Leo

CHIRPS
USER_ID ID
41      7
41      12

LIKES
USER_ID CHIRP_ID LIKED_BY
41      7        22
41      7        18
41      12       22
41      12       18
```

***

## Relational systems: sharding via an extra layer

When you need SQL joins and relational guarantees at scale, you typically add a routing/resharding layer that presents a single SQL surface to the application and handles query routing and online resharding.

### Vitess (MySQL)

Vitess is a popular sharding/proxy layer originally built at YouTube (used by Slack and other large services). The application talks to Vitess as if it were a single MySQL instance; Vitess routes queries to the correct shard and handles online resharding for you.

![A minimal architecture diagram showing an app at the top, a Vitess routing layer in the middle, and a MySQL database at the bottom with arrows indicating request flow. The Vitess logo and name appear prominently.](https://mintcdn.com/kodekloud-c4ac6d9a/U9fTv2NKZBAqmNMH/images/System-Design-Database-Sharding/Sharding-in-Practice/How-Real-Databases-Shard-for-You/vitess-routing-layer-app-mysql-architecture.jpg?fit=max\&auto=format\&n=U9fTv2NKZBAqmNMH\&q=85\&s=13d0342709892fbea7a33feef84e4537)

When you add a shard, Vitess performs online resharding using the same four general steps most systems use: copy data, catch up with concurrent writes, cut over traffic to the new shard, then delete the old copy.

![A dark-themed architecture diagram showing an "App" connecting through a routing layer labeled "VITESS" to five database shards (Shard 0–4). The top shows a four-step process with step 2 "Catch Up" highlighted, and Shard 2 and Shard 4 visually emphasized.](https://mintcdn.com/kodekloud-c4ac6d9a/U9fTv2NKZBAqmNMH/images/System-Design-Database-Sharding/Sharding-in-Practice/How-Real-Databases-Shard-for-You/vitess-app-routing-shards-catchup-step2.jpg?fit=max\&auto=format\&n=U9fTv2NKZBAqmNMH\&q=85\&s=4a2b15b8970190c59e01fb79202bf01d)

Behind Vitess, each shard is a standard MySQL instance; the difference is Vitess hides shard topology and migration from the application.

### Citus (Postgres)

Citus is a Postgres extension that exposes a single Postgres surface and distributes queries to the nodes that hold the relevant rows. If you shard related tables by the same key (for example `user_id`), the relevant rows for a user (profile, posts, likes) can be co-located on one worker node so joins remain local and fast.

![A diagram of the Citus distributed database architecture showing an app talking to a routing layer that shards data across multiple PostgreSQL nodes (Shard 0–3). A small country\_codes table (IN, US, GB) is shown as an example of a tiny, denormalized table.](https://mintcdn.com/kodekloud-c4ac6d9a/U9fTv2NKZBAqmNMH/images/System-Design-Database-Sharding/Sharding-in-Practice/How-Real-Databases-Shard-for-You/citus-sharded-postgres-architecture-diagram.jpg?fit=max\&auto=format\&n=U9fTv2NKZBAqmNMH\&q=85\&s=5d1627f690221e40123a09cfcd168221)

Citus supports copying small lookup/reference tables (e.g., `country_codes`) to every worker node. This is a standard optimization: replicate small, read-heavy tables to avoid cross-node joins.

Vitess and Citus preserve SQL and relational semantics while handling routing and online data movement for you. You still get joins and stronger transactional guarantees (compared to many NoSQL systems) if you design your sharding keys correctly.

***

## NoSQL systems: distribution built in

NoSQL systems typically embed the sharding logic inside the database and trade some cross-shard semantics for scalability and simpler operational models.

### Cassandra

Cassandra is a peer-to-peer distributed database: any node can accept a client request. The receiving node acts as a coordinator: it consults a consistent-hashing ring to determine which nodes own the data and forwards the request to them. There is no single primary machine.

![A dark-themed diagram titled "Cassandra" showing a user labeled "Chris" connecting through an app to a ring of database nodes, with several nodes highlighted (41) and arrows indicating data flow.](https://mintcdn.com/kodekloud-c4ac6d9a/U9fTv2NKZBAqmNMH/images/System-Design-Database-Sharding/Sharding-in-Practice/How-Real-Databases-Shard-for-You/cassandra-chris-app-ring-nodes-41.jpg?fit=max\&auto=format\&n=U9fTv2NKZBAqmNMH\&q=85\&s=aff3380192b0d965d5a7a805454fc265)

Cassandra maps each physical node to multiple points on the ring using virtual nodes (vnodes). This makes rebalancing smoother because adding a new machine takes many small ranges from many existing nodes rather than one large contiguous range.

![A dark-themed diagram showing Cassandra's consistent-hashing ring with orange dots around a circle labeled "Virtual Nodes." To the right are stacked database icons representing machines, with a dashed outline highlighting a "New Machine."](https://mintcdn.com/kodekloud-c4ac6d9a/U9fTv2NKZBAqmNMH/images/System-Design-Database-Sharding/Sharding-in-Practice/How-Real-Databases-Shard-for-You/cassandra-ring-virtual-nodes-new-machine.jpg?fit=max\&auto=format\&n=U9fTv2NKZBAqmNMH\&q=85\&s=2c6aa67e085059c38592536f2eefcd9b)

Cassandra does not support cross-shard joins or multi-row transactions across arbitrary partitions in the way relational databases do. Data modeling is therefore often denormalized: duplicate the data needed for efficient local reads rather than relying on joins at query time.

![A dark-themed diagram titled "Cassandra" showing two separate data stores: on the left a "users" table with user\_id 18 (Leo) connected to "Leo's Data," and on the right a "likes" table listing likes (including Martin and Leo) connected to "Chris's Data."](https://mintcdn.com/kodekloud-c4ac6d9a/U9fTv2NKZBAqmNMH/images/System-Design-Database-Sharding/Sharding-in-Practice/How-Real-Databases-Shard-for-You/cassandra-users-likes-leo-chris-diagram.jpg?fit=max\&auto=format\&n=U9fTv2NKZBAqmNMH\&q=85\&s=0d10a1d306339c528318a1ae204059c2)

Operationally, Cassandra is commonly self-hosted and operated by the team using it; you manage the machines, repair, compaction, and topology changes.

### DynamoDB

DynamoDB is a fully managed key-value / document store. Amazon runs the machines, handles partitioning, rebalancing, and splits. Your main responsibility is selecting the partition key (DynamoDB’s shard key).

![A stylized DynamoDB diagram showing an app routing requests to multiple partitions with "user\_id" as the partition key. One partition is highlighted (labeled "Lena 500") with read/write throughput bars marked 3,000 reads/s and 1,000 writes/s.](https://mintcdn.com/kodekloud-c4ac6d9a/U9fTv2NKZBAqmNMH/images/System-Design-Database-Sharding/Sharding-in-Practice/How-Real-Databases-Shard-for-You/dynamodb-app-routing-partitions-userid-lena500.jpg?fit=max\&auto=format\&n=U9fTv2NKZBAqmNMH\&q=85\&s=bdf254b9acb8617bcb033e317ecac6f9)

Important constraints:

* DynamoDB automatically splits and rebalances partitions as data grows.
* A single partition key value cannot be split across physical partitions; a very hot key (a single popular user) can become a throughput hotspot.
* Practical per-key limits (approximate for small items): \~3,000 small reads/s and \~1,000 small writes/s. Exact limits depend on item size and provisioned vs on-demand mode.

Design for per-partition limits. If one user or key becomes extremely popular (a “hot key”), you must mitigate with caching, request fanout, or by changing your data model (for example, adding time-based suffixes to keys or sharding at the application level).

DynamoDB also does not support joins; denormalization and single-table design patterns are common.

### MongoDB

MongoDB stores semi-structured documents and supports sharding via a router process (mongos). Data is split into ranges of shard key values called chunks. When chunks become imbalanced the balancer moves them between shards using the copy → catch-up → cut-over → delete lifecycle.

Queries that include the shard key are targeted to a single shard:

```javascript theme={null}
db.users.find({ user_id: 41 })
```

Queries that do not include the shard key require a scatter-gather: the router asks every shard and merges the results, which is less efficient:

```javascript theme={null}
db.users.find({ joined: { $gte: ISODate("2023-01-01"), $lt: ISODate("2023-02-01") } })
```

Scatter-gather queries are supported, but they can be slow at scale because they touch all shards.

***

## Quick comparison

| Database / Layer | Distribution model | Joins & Transactions | Sharding behavior | Operational model |
| - | - | - | - | - |
| MySQL + Vitess | External proxy routes to MySQL shards | SQL joins supported (when co-located) | Vitess performs online resharding (copy → catch up → cut over → delete) | Self-hosted or managed (Vitess runs for you) |
| Postgres + Citus | Extension distributes queries to workers | SQL joins supported across co-located data | Co-locate related tables by shard key; replicate small lookups | Self-hosted or cloud-managed |
| Cassandra | Peer-to-peer ring with vnodes | No cross-shard joins; eventual consistency tradeoffs | Consistent hashing with virtual nodes; coordinator nodes | Typically self-hosted |
| DynamoDB | Fully managed by AWS | No joins; denormalize | Partition key chosen by user; AWS splits partitions; single key cannot span physical partitions | Fully managed |
| MongoDB | Router (mongos) + ranged chunks | Document model; targeted queries when shard key present | Range sharding with chunk migration (copy → catch up → cut over → delete) | Self-hosted or managed (Atlas) |

***

## Choosing a database and a shard key

Consider three main factors:

* Query patterns to optimize: which queries must be low latency and single-shard?
* Required cross-shard consistency and joins: do you need relational transactions and joins, or can you denormalize?
* Operational model: do you prefer fully managed (DynamoDB, Atlas) or self-hosted control (Cassandra, Vitess/Citus)?

Best practices:

* Pick a shard key that makes the most common queries targeted (single-shard).
* Co-locate related tables on the same shard key in relational sharded systems (Vitess/Citus) to keep joins local.
* If you use a managed system (DynamoDB), design for per-key throughput limits and avoid hot keys.
* For NoSQL systems, adopt denormalized data models where joins would require scatter-gather behavior.

If your workload requires frequent multi-table joins and strong transactional guarantees, favor relational sharding layers (Vitess/Citus). If you need horizontal scale with simpler operational overhead or are building a high-throughput key-value service, consider NoSQL solutions but design for denormalization and hot-key mitigation.

***

## Summary

* Relational systems (MySQL/Postgres) preserve SQL joins and stronger correctness; sharding is commonly provided by an external layer (Vitess for MySQL, Citus for Postgres).
* Cassandra and DynamoDB embed distribution: Cassandra is peer-to-peer with vnodes and coordinator routing; DynamoDB is fully managed and requires careful partition-key design.
* MongoDB shards by range and uses a router (mongos) with chunk migrations that follow the same online-migration steps.
* Choosing a database and shard key is always a tradeoff among query patterns, operational preferences, and the level of cross-shard semantics you need.

## Links and references

* [Vitess](https://vitess.io/)
* [Citus](https://www.citusdata.com/)
* [Apache Cassandra](https://cassandra.apache.org/)
* [Amazon DynamoDB](https://aws.amazon.com/dynamodb/)
* [MongoDB Sharding](https://www.mongodb.com/docs/manual/sharding/)

> **[Watch Video](https://learn.kodekloud.com/user/courses/database-sharding/module/1a567ebf-0997-46eb-9a16-b6b2c530bd5f/lesson/e2c88905-a7d3-4092-bbb0-2f48f93858cb)**


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.