How DynamoDB Partition Keys Work
Your partition key isn't a column — it's an address. DynamoDB hashes that key and the hash decides which physical machine stores the item. Pick the key well and load spreads; pick it badly and one server takes the heat.
How do DynamoDB partition keys work?
DynamoDB runs your through an internal hash function, and that hash decides which physical partition stores the item. The key isn't sorted or indexed like a SQL column — it's an address. Pick a high-cardinality key and load spreads across many partitions; pick a low-cardinality one and a single partition takes all the heat.
- The key is hashed, not sorted. DynamoDB runs your partition key through an internal hash to choose a partition. Two adjacent values land nowhere near each other on disk.
- A partition is a real storage unit. Each one caps out around 10 GB, 3,000 read units/sec and 1,000 write units/sec. Your traffic is divided by how many partitions your keys spread across.
- Hot keys are the footgun. Funnel most requests at one partition-key value and you throttle on that partition while the rest of the table sits idle.
- High-cardinality keys win. The more distinct, evenly-hit key values you have, the more partitions absorb the load.
Start with what the key actually does
Coming from SQL, a primary key is a sorted, indexed column you JOIN and ORDER BY on. In DynamoDB the partition key (sometimes called the hash key) does
something different: it decides placement.
DynamoDB feeds the partition key into an internal hash function. The output maps to a keyspace, and the keyspace is sliced into ranges — each range owned by a physical partition. That partition is real storage on a real node.
So the partition key answers one question: which machine holds this item? The sort key, if you have one, only orders items within that machine. It plays no part in placement.
Follow one write through the hash
Say you run a SaaS that ingests device readings. Your table SensorReadings uses
a partition key deviceId and a sort key readingTs. You write a reading for
deviceId = "vac-7741".
Here's the path that write takes — from your key to the disk it lands on:
The write for vac-7741 is hashed to a point in the keyspace, that point falls in
P2's range, and the item lands on P2 — ordered there by readingTs.
The thing to internalise: "vac-7741" and "vac-7742" are one character apart,
but their hashes are unrelated. They almost certainly live on different
partitions. There is no "nearby" in the partition keyspace.
This is the consistent-hashing idea DynamoDB inherited from the original design — the 2007 Amazon Dynamo paper ("Dynamo: Amazon's Highly Available Key-value Store") spread keys across nodes by hashing exactly so no single node became a bottleneck.
Paste a list of partition-key values below to see how a hash scatters them across buckets. A high-cardinality set spreads evenly; reuse one value and it all piles into a single bucket — the hot partition the next section is about.
This is a teaching hash for intuition, not DynamoDB's real internal hash — the actual function, keyspace, and partition boundaries are AWS internals. Use it to build a feel for spread vs skew, not to predict which physical partition a key lands on.
Respect the partition's hard limits
A physical partition is finite. Per the AWS DynamoDB Developer Guide, each one holds up to about:
| Limit | Per partition |
|---|---|
| Storage | ~10 GB |
| Read throughput | 3,000 read units/s |
| Write throughput | 1,000 write units/s |
When a partition fills past 10 GB, or your provisioned throughput needs more room, DynamoDB splits it — the keyspace range is divided and items redistribute across more partitions. This is automatic; you don't trigger it.
The catch: a split spreads items by their hash. If every hot request targets a single partition-key value, splitting doesn't help — all that traffic still hashes to the same point. You can't split a single key's load across partitions.
Name the trap: the hot partition
A hot partition is the classic footgun. It happens when one partition-key value (or a tiny set of them) absorbs a disproportionate share of traffic.
Concrete failure: you switch SensorReadings to a partition key region with
values like "us-east", "eu-west". Three regions means three key values means —
at most — three partitions doing real work. Slam "us-east" with reads and it
throttles at 3,000 RCU while the table's total provisioned capacity sits unused.
DynamoDB's adaptive capacity softens this — it can shift unused throughput toward a busy partition, and isolate a single very-hot key onto its own partition. AWS detailed this in the re:Invent "Advanced Design Patterns for DynamoDB" deep-dive sessions. But adaptive capacity buys time, not immunity: it can't subdivide the load of one individual key. Design for spread; don't lean on the safety net.
Choose a high-cardinality key
The fix is cardinality — the number of distinct key values, and how evenly traffic hits them.
- Low cardinality (
region,status,true/false): few partitions, traffic concentrates, you throttle early. - High cardinality (
deviceId,userId, an order ID): many values hashing across many partitions, load spreads, headroom grows.
Coming from SQL you'd happily index a status column and filter on it. As a
DynamoDB partition key that's a trap — it can't spread. Keep low-cardinality
attributes as filters or as a secondary index's sort key,
never as the thing that decides placement.
When a naturally good key still skews — a handful of whale tenants outpacing the
rest — add a suffix to fan one logical value across N partitions, e.g.
tenantId#3 for a sharded write path. You re-aggregate on read.
To target items within a partition once your key is spread, you'll write a
KeyConditionExpression on the sort key. You can assemble one against your own
schema in the DynamoDB expression builder
before wiring it into code:
deviceId = "vac-7741" AND readingTs BETWEEN "2026-06-01" AND "2026-06-30"
That reads one device's June window from a single partition — a Query, not a
Scan. The partition key pins the machine; the sort-key
condition narrows the rows.
Pitfalls and next steps
- Don't pick a key by what reads well in SQL. Pick it by what spreads. Cardinality first, query convenience second.
- Don't assume the table's total capacity is yours per key. Throughput is per-partition; one hot value can throttle while the table looks idle.
- Don't fight a split. It's automatic and hash-driven — your job is to give it enough distinct keys to spread across.
Once your key spreads cleanly, the next decisions are how to lay out items inside a partition — see single-table design — and when a secondary index is the right tool for a second access pattern.
Download DynoTable to browse your real partitions and key distribution, and spot a hot key before it pages you.