Advanced6 min read

DynamoDB physical partitions

A physical partition is the unit DynamoDB actually stores your data on: a slice of SSD, replicated across Availability Zones, holding one slice of your key space. Your table is a logical thing. Partitions are where the bytes — and the throughput limits — really live.

How do DynamoDB partitions work?

DynamoDB stores your table across physical partitions — SSD slices replicated across Availability Zones. Each one caps at ~10 GB, 3,000 read units/sec, and 1,000 write units/sec. The hash of your decides which partition an item lands on, and DynamoDB splits partitions automatically as they grow or get hot.

  • Every partition caps at ~10 GB of storage, 3,000 read units/sec, and 1,000 write units/sec. Those ceilings are per partition, not per table.
  • The hash of your partition key picks the partition. Items with the same key land together; one hot key means one hot partition.
  • DynamoDB splits partitions for you — on size, and on sustained heat — but it can't fix a key that funnels all traffic to one place.
  • Throttling with capacity to spare is the tell. A ProvisionedThroughputExceeded error while your table sits at 5% usage means a single partition is maxed out.

How an item finds its partition

DynamoDB feeds your partition-key value through an internal hash function. The hash output picks the physical partition. Same key in, same partition out — every time.

Coming from SQL, there's no analogue. There's no index B-tree you tune, no shard key you assign by hand. The placement is a hash you don't control and never see.

Items sharing a partition key form an item collection, stored together and sorted by sort key. That's what makes a Query on one key cheap — it reads one contiguous run on one partition. (See Query vs Scan.)

Take a match-event store for a game. The table keys are arenaId (partition) and eventKey (sort):

# Item
arenaId    = "ARENA#7f3a"
eventKey   = "EVT#1719100800#a91c"
playerTag  = "Nightjar"
dmgDealt   = 412

Every event for arena 7f3a hashes to the same partition and stacks in sort-key order. Great for "read this match's timeline." A liability if that one arena gets all the traffic.

The three ceilings every partition enforces

A single partition is designed to deliver at most:

LimitPer partitionCounted as
Storage~10 GBraw item bytes
Read capacity3,000 read units/sec1 RU = one 4 KB strongly-consistent read
Write capacity1,000 write units/sec1 WU = one 1 KB write

Source: the AWS Best practices for designing partition keys guide.

Item size scales the math. A 20 KB item costs 5 read units per strongly-consistent read, so one partition serves ~600 such reads/sec before it throttles — not 3,000. Round write cost up per 1 KB, read cost up per 4 KB.

The trap: these are partition limits, not table limits. Your table can be provisioned for 40,000 WCU and still throttle, because all the writes are pounding one partition that tops out at 1,000.

How partitions split

DynamoDB adds partitions automatically in two cases. You never run a command.

Split on size. When a partition fills toward ~10 GB, DynamoDB splits its key range in two and moves half the items to a new partition. Storage grows transparently; your reads and writes keep working throughout.

Split for heat. When a partition takes sustained traffic near its throughput ceiling, DynamoDB splits the hot key range so each half lands on its own partition. AWS calls this the split-for-heat mechanism. Short throttling bursts that stop on their own usually mean a split just happened.

SizeHeatPartition A~10 GB / hotSplittrigger?Range halvedby stored bytesRange halvedby trafficTwo partitionsown capacity eachOne hot KEYstill on one partition

Splitting buys room across many keys, but the bottom node is the catch: a split divides a key range, never a single key.

Why a hot key beats the splitter

Here's the footgun. Splitting redistributes ranges of partition keys. If your traffic concentrates on one key value, every request hashes to the same partition, and there's no range left to divide.

If arena 7f3a is a tournament final pulling 4,000 writes/sec while every other arena is idle, you'll throttle at 1,000 — and a split can't help, because all 4,000 share one key. The newer KeyRangeThroughputExceeded throttle reason names exactly this: one partition's key range, not the table, is over its limit.

The fix is in the data model, not the capacity slider. Write-shard the hot key: append a small suffix so one logical arena spreads across N physical partitions.

arenaId = "ARENA#7f3a#3"   # shard 0..9, chosen per write

Reads then fan out across the shards and merge client-side. You can prototype the key shapes and the Query for each shard with the DynamoDB Expression Builder before you touch a line of application code.

One nuance: the LSI exception

There's one case where storage is capped per partition key. Without a Local Secondary Index, an item collection auto-splits across as many partitions as it needs — billions of sort-key values are fine.

Add an LSI, and the whole collection for one partition key must fit in a single 10 GB partition, because the LSI shares it. That's the per-PK cliff covered in GSI vs LSI — another reason most teams reach for GSIs.

Designing so partitions stay cool

The lever you actually control is the partition key. Pick one with many distinct values relative to row count, so traffic spreads evenly. (More patterns in single-table design.)

  • High-cardinality key. A per-user or per-tenant key beats a per-day or per-status key that everyone hammers at once.
  • Watch for known hot keys. A "current tournament" or "today" value is a concentration risk before you ship, not after.
  • Shard the unavoidable hot key. When one key must take outsized traffic, a suffix is the standard escape hatch.

Throttling with capacity to spare is your signal that one partition is hot. Inspect the offending items and rehearse a sharded key layout in DynoTable — point it at your own table, find the key that's overloaded, and model the fix before it pages you.

Updated