← Back to blog

2026-07-16 · 8 min read

DynamoDB Data Modeling for DevOps Engineers

A practical introduction to DynamoDB data modeling, partition keys, single-table design, access patterns, and the mistakes that cause hot partitions and runaway cost.

#aws#dynamodb#serverless#data#cloud
DynamoDB Data Modeling for DevOps Engineers

DynamoDB Data Modeling for DevOps Engineers

DynamoDB is fast, serverless, and scales endlessly, if you model your data the way it wants. Coming from relational databases, the instinct is to normalize and query flexibly. DynamoDB punishes that. Here's the mental shift and the practical rules.

The core rule: model around access patterns, not entities

In SQL you design tables around your data and write whatever queries you need later. In DynamoDB you do the opposite: list your access patterns first, then design keys so each pattern is a single, efficient lookup. If you don't know your queries, you can't model DynamoDB well.

Partition key and sort key

Every item has a partition key (PK) that determines which physical partition it lives on, and optionally a sort key (SK) for ordering and range queries within a partition.

  • Good PK: high-cardinality, evenly accessed (e.g. USER#123). Spreads load.
  • Bad PK: low-cardinality or skewed (e.g. status with values active/inactive). Creates a hot partition: one partition gets hammered, throttling everything on it.

Single-table design

The DynamoDB-native pattern is to put many entity types in one table, distinguished by key patterns:

PK              SK                Attributes
USER#123        PROFILE           name, email
USER#123        ORDER#2026-01-01  total, status
ORDER#555       ITEM#1            sku, qty

This lets one query fetch a user and their orders in a single round trip (PK = USER#123). It feels alien at first, but it's how you avoid N+1 lookups.

Secondary indexes for extra access patterns

When you need to query by something other than the PK:

  • GSI (Global Secondary Index): a different PK/SK; eventually consistent; its own capacity.
  • LSI (Local Secondary Index): same PK, different SK; strongly consistent; set at table creation.

A common pattern: an "inverted index" GSI that flips PK and SK so you can query the relationship the other direction.

Billing: on-demand vs provisioned

  • On-demand: pay per request, scales instantly, zero capacity planning. Best for spiky or unknown traffic, and the right default for most apps.
  • Provisioned (+ auto-scaling): cheaper for steady, predictable, high volume.

(My aws-serverless-api-terraform uses on-demand, nothing to tune.)

The mistakes that bite

  • Hot partitions from a low-cardinality PK → throttling. Pick a PK that spreads evenly.
  • Scans in production. Scan reads the whole table; it's fine for admin/batch, a disaster on a hot path. Design so you Query, not Scan.
  • Unbounded item growth. Items max out at 400 KB; don't append forever to one item.
  • Treating it like SQL. No joins, no flexible ad-hoc queries. If you need those, you modeled wrong (or you need a different database).

A practical workflow

  1. Write down every access pattern ("get user by id", "list a user's orders newest-first", …).
  2. Design PK/SK so each pattern is one Query or GetItem.
  3. Add GSIs only for patterns the main key can't serve.
  4. Start on-demand billing; switch to provisioned only with steady, proven volume.
  5. Load-test for hot partitions before you trust it at scale.

DynamoDB rewards up-front modeling and punishes improvisation. Do the access-pattern work first and it's one of the best databases in the cloud; skip it and you'll fight it forever.


Building serverless on AWS and unsure how to model your data? That's part of my consulting, reach out.

Share:LinkedInXWhatsApp

Related articles

Reactions & comments