Building Blocks

DynamoDB

Partition and sort keys, single-table design, and the eventual-vs-strong read trade-off made explicit per request.

12 minMediumdatabasesbuilding-blocks

Database Fundamentals drew the SQL-vs-NoSQL line in general terms. DynamoDB is the concrete, frequently-named example on the NoSQL side of that line — a managed key-value/wide-column store where the trade-offs that lesson described abstractly become specific, load-bearing design decisions.

The primary key decides everything

A DynamoDB table has a partition key, and optionally a sort key alongside it. The partition key alone decides which physical partition an item lives on — internally, by hashing it, the same idea Consistent Hashing covers in general. Where a sort key exists, items sharing a partition key are stored together, ordered by it — which is what makes a query like "all orders for this customer, most recent first" a single efficient read instead of a scan. Getting this pair wrong is the most common way a DynamoDB design goes sideways: unlike a relational table, the key design isn't something you fix later with an index — it has to match the access pattern from the start.

Single-table design

Relational modeling normalizes first and figures out queries later; the common DynamoDB pattern inverts that — list every access pattern the application actually needs up front, then design item keys so each pattern is a single efficient read, often storing several unrelated entity types in one table distinguished by key prefix. This is denormalization taken further than the fan-out-on-write example in Database Fundamentals — duplication is the accepted cost of avoiding joins DynamoDB doesn't support at all.

Capacity: provisioned vs. on-demand

Provisioned capacity reserves a fixed read/write throughput ahead of time — cheaper at steady, predictable volume, but a spike beyond it gets throttled unless auto-scaling catches up in time. On-demand capacity bills per request with no pre-reservation — simpler operationally and safer against unpredictable spikes, at a higher per-request cost. Naming which one fits a given traffic pattern is a real answer; "DynamoDB scales automatically" without picking one is not.

Secondary indexes

The partition/sort key pair supports exactly the access patterns it was designed for — anything else needs a secondary index. A local secondary index (LSI) keeps the same partition key but a different sort key, created only at table creation, and can be read with strong consistency. A global secondary index (GSI) can use an entirely different partition key, can be added after the table exists, but is only eventually consistent — a write to the base table isn't guaranteed to be visible through the GSI immediately.

Consistency is a per-read choice

Reads default to eventually consistent — cheaper, and usually fine, but a read immediately after a write can return stale data. A caller can request a strongly consistent read instead, at roughly double the cost and somewhat higher latency, when correctness after a write genuinely matters — the same strong-vs-eventual decision Consistency and CAP frames generally, made explicit per request rather than fixed for the whole system.