How it works
The explanation, with examples you can run.
Keys decide everything
The primary key is either a partition key alone or a partition key plus a sort key. DynamoDB hashes the partition key to choose a physical partition; items with the same partition key are stored together, ordered by sort key. That allows two efficient operations: GetItem by full key, and Query for one partition key with a condition on the sort key. Anything else is a Scan of the whole table, which is slow and expensive at scale.
{ "PK": "CUSTOMER#81", "SK": "ORDER#2026-10-16#5531", "total": 42.50, "status": "paid" }With this design, "all orders for customer 81, newest first" is one Query on PK = CUSTOMER#81, reading the sort key backwards. Additional access patterns get global secondary indexes, which are asynchronously maintained copies keyed differently. The discipline is to list the queries first and design keys for them, the opposite of relational modelling.
Hot partitions
Each partition can serve up to 3,000 read units and 1,000 write units per second. DynamoDB splits partitions and moves capacity to busy ones automatically (adaptive capacity), but it cannot split a single partition key value's traffic beyond that limit. Keys that concentrate traffic (a date, a status, a tenant that is much bigger than the rest, a global counter) get throttled while the rest of the table idles. Fixes: choose a higher-cardinality key, add a random or computed suffix to spread one logical key over several (write sharding), and cache hot reads.
Capacity modes
- On-demand is the default and recommended mode. You pay per request; a table instantly handles up to double its previous peak, and grows beyond that over time. Throttling is still possible if traffic more than doubles within 30 minutes, or if one key is hot.
- Provisioned sets read and write capacity units per second, usually with auto scaling. It is cheaper for steady, predictable traffic, but sudden spikes above capacity are throttled until scaling catches up.
Consistency and other details
Reads are eventually consistent by default, and usually current within a second. A strongly consistent read (ConsistentRead: true) returns the latest committed write, costs twice the read capacity, and is not available on global secondary indexes. Conditional writes (ConditionExpression) give optimistic locking and create-if-absent; transactions group up to 100 actions atomically. Streams publish every change for triggers and replication, TTL deletes expired items for free, and global tables replicate a table to other Regions.
The common failures are a hot key, a design that needs scans, forgetting that GSIs lag, and very large items that make every read expensive.
Check yourself
3 questions. Get them all right to finish this topic.
0 of 3 right so far. Get all three to finish this topic.