-
Notifications
You must be signed in to change notification settings - Fork 0
Recipes
Pattern-first pages for common DynamoDB problems that feel trivial in SQL but need non-obvious shapes here. Audience: developers moving from SQL to DynamoDB — usually because of Lambda cost, cold-start latency, or serverless-native ergonomics — who hit the "how do I even do $X?" wall.
Every recipe opens with the SQL-equivalent question, shows the pattern against real toolkit primitives, tables the cost / capacity tradeoffs, and calls out "when this doesn't fit" honestly. None of them is "the only way" — the closing sections list the alternatives you might reach for instead.
Recipes answer "how do I do X". For the design-level layer — how to shape keys, tables, paging, and URLs in the first place — see the guides: Hierarchical data walkthrough, Key expression patterns, Multi-type tables, Pagination, Mass operation semantics, URL schema design.
| If you want to… | Start here |
|---|---|
List every record of a "type" across every partition (SELECT * WHERE kind = 'state') |
List records of a tier |
List every record of a type within one partition (SELECT * WHERE state = 'TX' AND kind = 'facility') |
List records of a tier within a partition |
| Finer per-tier control — different projections, sharding at scale | Per-tier sparse GSI markers |
| Short-lived holds with auto-expiry (car reservation, meeting-room booking, flash sale) | Reservation with auto-release |
| Reduce GSI storage + write costs on wide base items | Keys-only GSI with runtime projection |
Delete / clone / move a subtree (DELETE CASCADE) |
Cascade subtree operations |
| Query a hierarchical subtree (children / self+children / prefix-narrow) | Querying subtrees with buildKey |
Type-safe REST filters from URL query strings (?eq-status=A&btw-year=-2020-2024) |
Filter URL grammar |
Free-form text search over a small dataset (?search=term) |
Text search |
| Bulk backfill / sweep / migration that resumes across Lambda invocations | Resumable mass operations |
| Create / extend / verify a DynamoDB table from the same declaration the app uses | Provisioning workflow |
The SQL "one table per entity type" gets packed into a single DynamoDB table via composite keyFields + a structuralKey. These recipes cover the three canonical "list everything of type X" access patterns.
-
List records of a tier — sparse GSI keyed on the auto-populated
typeField. Simplest cross-partition tier listing; one GSI covers every tier. "All states globally" / "all vehicles globally" / "all facilities globally." - Per-tier sparse GSI markers — one GSI per tier with a per-tier marker attribute. Finer control over projection + write cost; sharded-marker variant handles hot-partition risk at the leaf tier.
- List records of a tier within a partition — sparse LSI sharing the base pk. Cheapest option when the listing is always scoped to a partition you already know ("all facilities under TX", never "all facilities globally").
Optimistic concurrency + scope-freeze + resumable cleanup sweeps, composed.
-
Reservation with auto-release — user holds a resource for N minutes; expired holds auto-release on read and get swept on a schedule. Composes
versionField(OC) +createdAtField+asOf(scope-freeze) +deleteListByParams(resumable sweep). Honest caveats on ABA, DynamoDB-native-TTL-as-backstop, and stealing expired holds.
Shape the GSI for the read traffic you actually have. The toolkit composes the hand-rolled patterns as declarative options.
-
Keys-only GSI with runtime projection — declare a GSI with
projection: 'keys-only'+indirect: true. Reads Query the GSI for keys, thenBatchGetItemthe base table with the caller's per-callfields. Cheap GSI storage + writes; rich runtime projections. Cost tables compareall/keys-only/INCLUDEtradeoffs at real item sizes.
See also Key and field design for the design framework this recipe applies.
DynamoDB has no FKs, no ON DELETE CASCADE, and no native triggers. Hierarchy has to be encoded in the sort key. These recipes cover the two shapes of access pattern that result: reading a subtree, and mutating one.
-
Querying subtrees with
buildKey—adapter.buildKey(values, options?)composes the three naturalKeyConditionExpressionshapes for a hierarchy: children-only (default), self + descendants ({self: true}), narrow-prefix ({partial: 'Dal'}). Covers thegetListUndersugar, the implicit sibling-prefix invariant for{self: true}, and the GSI-targeted-query deferral (drop tobuildKeyConditionprimitive for now). -
Cascade subtree operations —
deleteAllUnder/cloneAllUnder[By]/moveAllUnder[By]against compositekeyFieldswithrelationships: {structural: true}. Leaf-first / root-first pagination, constructive-before-destructive moves,MassOpResultpartial-failure surfacing, Lambda-budget resumability.
The URL grammars the handler + framework adapters expose to clients, with how they compile down to DynamoDB expressions.
-
Filter URL grammar —
?<op>-<field>=<value>(Option W) end-to-end.filterabledeclaration + per-field type coercion, first-character delimiter forin/btw, auto-promotion ofeq-on-pk / range-on-sk clauses toKeyConditionExpression, composition withoptions.filteron mass ops. Cost tables for KCE-only / KCE+FE / FE-only paths. -
Text search —
?search=termagainst lowercasedsearchablemirror columns. Write-side prepare hook, read-side OR across declared mirrors, case sensitivity + unicode folding tradeoffs, when to reach for OpenSearch / Algolia instead.
Patterns for data maintenance, backfills, and table-shape management.
-
Resumable mass operations —
MassOpOptions(maxItems,resumeToken,asOf,ifNotExists/ifExists) +MassOpResult(processed,skipped,failed,conflicts,cursor?). EventBridge / Step Functions / driver-script orchestration patterns; error bucketing rules (versionField conflicts vs plain CCFs);maxItemssoft-cap semantics. -
Provisioning workflow —
planTable(read-only) /ensureTable(ADD-only apply) /verifyTable(drift detection). Descriptor-row round-trip for metadata DescribeTable can't see (filterable,searchable,versionField, …). Placement in IaC-owned vs toolkit-owned vs CLI-only deploy pipelines.
Recipes follow a consistent shape so readers know where to look:
- Title + SQL-equivalent question in a blockquote at the top. Tell the reader what problem the recipe solves, framed in SQL terms they already know.
- "Why DynamoDB makes you compose" (or "Why X gets expensive" / "Why you can't just Y") — one or two paragraphs that name the specific DynamoDB primitives missing vs SQL, and why the naive approach fails.
- The pattern — runnable declaration (Adapter + indices + hooks). Minimal but complete.
- Worked code for each operation the pattern supports.
- Cost + capacity — storage, RCU / WCU, partition-throughput ceilings. Tables where honest math informs the decision.
-
Alternatives or middle grounds — "
projection: 'all'vskeys-only," "DynamoDB native TTL vs custom sweep," etc. Recipes are opinionated; alternatives show the opinion is informed, not absolute. - When this fits / when it doesn't — bullet lists. If every point under "doesn't fit" applies to your use case, stop reading and pick a different pattern.
- Related — cross-references to Concepts / Adapter reference / other recipes.
Language rules of thumb:
- Names the SQL equivalent upfront, then drops the framing once the reader is oriented.
- Tables beat prose for cost / capacity / comparison sections.
- Every dollar figure or throughput number has a unit and a region (e.g., "$0.25/GB/mo in us-east-1"). If the number changes with partition size, say so.
- "When it doesn't fit" earns credibility. Avoid selling the pattern past its range.
- Concepts — the vocabulary every recipe assumes (pk, sk, GSI, LSI, projection, structural key, technicalPrefix).
- Key and field design — how to choose partition / sort keys, when to reach for LSI vs GSI, which technical fields actually earn their bytes. Read before you shape a new table; recipes apply these choices to specific problems.
-
Adapter: Constructor options — full declaration reference for
keyFields,structuralKey,indices,versionField,createdAtField,typeField,relationships, etc.
Start here
- Getting started
- Concepts
- Key and field design
- Compatibility
- Migration: v2 to v3
- SDK v2 to v3 cheat sheet
Guides
- Hierarchical data walkthrough
- Key expression patterns
- Multi-type tables
- Pagination
- Mass operation semantics
- URL schema design
Adapter
- Adapter
- Constructor options
- CRUD methods
- Mass methods
- Batch builders
- Hooks
- Raw marker
- Indirect indices
- Transaction auto-upgrade
Expression builders
Batch / transactions / mass / paths
REST surface
Framework adapters
Recipes
- Recipes index
- List records of a tier
- Per-tier sparse GSI markers
- Tier within a partition
- Reservation with auto-release
- Keys-only GSI, runtime projection
- Cascade subtree operations
- Querying subtrees with buildKey
- Filter URL grammar
- Text search
- Provisioning workflow
- Resumable mass operations
History