Recipe

DynamoDB design patterns

DynamoDB rewards single-table thinking. Instead of normalizing across many tables, you collapse your access patterns into one table with overloaded partition and sort keys. This recipe walks through the patterns Meridian uses in production to keep reads under 10ms and writes idempotent at scale.

1.Model access patterns first

Before you touch a schema, list every query the app needs: by user, by tenant, by date range. DynamoDB cannot bolt on indexes later without a backfill. The partition key (PK) and sort key (SK) must answer every read in one Query call.

2.Overload the sort key

One partition holds many entity types. A user partition stores the profile, sessions, and audit log rows, each tagged by an SK prefix like PROFILE#, SESSION#, and AUDIT#. A begins_with query fetches just the slice you need.

PK              SK                      Type
USER#42         PROFILE#                user
USER#42         SESSION#2026-06-27      session
USER#42         AUDIT#2026-06-27T14:02  audit
TENANT#acme     USER#42                 membership
TENANT#acme     USER#43                 membership

3.Make writes idempotent

Every write should carry a deterministic key the caller can replay. Use a ConditionExpression of attribute_not_exists(PK)to dedupe at the database layer. Pair it with a TTL on transient rows so the table self-trims without a sweeper job.