Advanced7 min read

How DynamoDB Request Routing Works

Every read or write you send hits a fleet of stateless request routers first. A router hashes your , maps the hash to the storage node that owns that key's data, and forwards the request there. That one hop is why a key lookup costs the same whether the table holds a thousand items or a billion.

How does DynamoDB request routing work?

DynamoDB routes every request through a stateless request router fleet that hashes your , maps the hash to the single storage node owning that partition, and forwards the read or write there. Routing is a pure function of the key's hash, so one lookup costs the same whether the table holds a thousand items or a billion.

  • The request router is the front door. It's a stateless fleet that takes your request, hashes the partition key, and routes it to the storage node holding that partition — no scanning, no full-table knowledge needed.
  • The partition key decides everything. Routing is a pure function of the partition key's hash. Same key, same node, every time — so GetItem is O(1), not O(table size).
  • One primary, two secondaries. A write lands on the partition's primary node, which replicates to two secondaries across Availability Zones before it's durable.
  • Bad keys defeat the design. A low-cardinality or key funnels traffic to one node — the routing is fine, your key is the problem.

Start with the problem routing solves

Coming from SQL, you picture a query planner: it reads statistics, picks an index, maybe scans. The cost scales with how much data it touches. That model doesn't fit a key-value store that has to answer in single-digit milliseconds at any size.

DynamoDB's answer is to make a single-item lookup a direct address, not a search. The partition key isn't a column you filter on — it's the input to a hash function that computes where the data physically lives. No statistics, no planner.

That's the trade you accept when you move off relational thinking: you give up ad-hoc query flexibility and get constant-time addressing in return.

Meet the request router

When a request arrives, it doesn't go straight to storage. It hits a request router — a stateless, horizontally scaled fleet that fronts the whole service. (AWS re:Invent "DynamoDB Deep Dive" sessions describe this front-end fleet.)

The router does three things and holds no data of its own:

  • Authenticates and authorizes the request against IAM.
  • Hashes the partition key to find the partition that owns it.
  • Forwards the request to the storage node for that partition.

Because routers are stateless, the service adds more of them under load. None of them is a bottleneck and none is a single point of failure — the same property the 2007 Amazon Dynamo paper built the original system around.

Follow one read through the router

Take a telemetry table for a drone fleet. Items are keyed by DroneId (partition key) and ReadingTs (sort key), with attributes like BatteryPct and AltitudeM.

You ask for the latest reading for one drone:

PK = "DRONE#A19F"
SK begins_with "2026-06-23"

Here's what the router does with it. The lead-in below traces the request top to bottom — read it as one downward flow.

Client: GetItemPK = DRONE#A19FRequest router(stateless fleet)Hash(DRONE#A19F) keyspace slotMap slot partitionthat owns the keyPrimary nodefor that partitionRead itemDRONE#A19F

The router hashes DRONE#A19F, maps it to the partition that owns that key, and forwards the read to that partition's primary storage node, which returns the item.

The key insight: the hash points at one partition out of however many the table has. The router never looks at other partitions, so adding drones — and partitions — doesn't slow this lookup down.

Know what a partition actually is

A partition is a unit of storage and throughput. Each one is capped (roughly 10 GB and a fixed slice of read/write capacity), and DynamoDB splits a partition when it outgrows either limit. Every item with a given partition key lives on the same partition, which is what makes a Query over one partition key cheap.

Each partition is replicated to three storage nodes spread across Availability Zones: one primary and two secondaries.

Node roleHandlesConsistency it can serve
PrimaryAll writes; strongly-consistent readsStrong (sees its own latest write)
SecondaryEventually-consistent reads; failoverEventual (may lag the primary)

A write goes to the primary, which replicates to the secondaries before acknowledging durability. A read is routed to the primary so it reflects the latest write. An read may be served by a secondary that hasn't caught up yet — half the cost, possibly stale.

Name the footgun: a hot partition key

Routing is only as good as your partition key. The hash spreads keys evenly, so if your keys have high cardinality and even traffic, load spreads across all nodes. Break either property and you get a hot partition.

Say you key that telemetry by Region instead of DroneId. Now every drone in us-east-1 shares one partition key — so every one of their reads and writes hashes to the same node. The router is doing its job perfectly; you've just funneled the whole fleet at a single partition's capacity.

You can't watch the router pick a node, but you can design keys that route well. When you build a key condition in the Expression Builder, the partition key you put on the left of PK = … is the exact value the router will hash — keeping that value high-cardinality is what keeps reads on separate nodes.

How this ties back to your access patterns

Request routing is the mechanism that makes the single-table design rules non-negotiable: you model around the partition key because the partition key is the address. It's also why a Query beats a Scan — a Query hits one partition through the router, while a Scan walks every partition in sequence.

Secondary indexes get their own partitions and their own routing: a GSI is routed by its own partition key, independent of the base table's, which is why a GSI can be hot even when the table isn't.

Next steps

Design keys that route to many nodes, not one. Sketch the PK = … condition in the Expression Builder to see exactly which value gets hashed, then download DynoTable to run those queries against your own tables and watch which partition keys actually carry your traffic.

Updated