Serverless (DynamoDB and serverless patterns) — Cheat Sheet (DVA-C02)
Verified against AWS documentation on 2026-10-12 · ⚠️ = changed vs older material: learn the value shown here (older practice material may say otherwise; full list in notes/dynamodb-guide.md#changed-vs-older-material) · ⚠️ unverified = AWS pages disagree or don't confirm it: don't rely on it · explanations and examples: notes/dynamodb-guide.md.
Tables items and primary keys
| Topic | Current facts | Memory hook |
|---|---|---|
| Simple primary key | Partition key only (HASH); no two items share a value |
One key, one item |
| Composite primary key | Partition key + sort key (HASH + RANGE); the pair is unique; items sharing a partition key form an item collection sorted by sort key |
Folder + file name |
| Key schema changes | Impossible after CreateTable: new access pattern → GSI, new key → new table |
Keys are carved in stone |
| Good partition key | High cardinality, evenly requested (user, order or device ID); avoid status, date, country, booleans | Many doors, even crowds |
| Item size | 400 KB maximum, attribute names included | Names pay rent too |
| Key value lengths | Partition key 1–2,048 bytes; sort key 1–1,024 bytes; key types S, N or B only | |
| Data types | Scalar S, N, B, BOOL, NULL · document L, M (up to 32 levels) · sets SS, NS, BS (unique, unordered, never empty) | |
| Dates | No date type: ISO 8601 string or epoch Number (TTL needs epoch seconds) | |
| Partition limits | 3,000 RCU and 1,000 WCU per partition; 10 GB per partition | 3-1-10 |
| ⚠️ Adaptive capacity | Always on, free, instant: a hot partition can use more of the table's throughput (up to the partition maximum); very hot items get partitions of their own; no published partition formula | Capacity follows the heat |
| Table lifecycle | CREATING → ACTIVE; early calls → ResourceNotFoundException; recreating → ResourceInUseException |
Wait for ACTIVE |
Read and write capacity units
| Rule | Current facts | Memory hook |
|---|---|---|
| 1 WCU | Each second: a 1 KB block written once | Write 1 |
| 1 RCU | Each second: a 4 KB block read once with strong consistency, or twice with eventual consistency | Read 4 |
| Transactional | Double: 2 RCU per 4 KB read, 2 WCU per 1 KB write (prepare + commit) | Transactions pay twice |
| Order of operations | Per second first → round each item up (1 KB or 4 KB) → multiply → ½ eventual or ×2 transactional → round up | Seconds, round, multiply |
Query sizing |
Sizes of all items read summed, filtered-out ones included, then rounded up once to 4 KB | Query pools its items |
Scan sizing |
Charged on items evaluated, not items returned | |
| Batch sizing | BatchGetItem and BatchWriteItem round every item separately, then add |
|
UpdateItem sizing |
Larger of the before and after images | |
| Failed condition | Still consumes WCU (at least 1) | |
| Filters and projections | Shrink the response, never the capacity consumed | Filters don't refund |
| GSI reads | Always eventually consistent: ½ RCU per 4 KB of projected data | |
| Measuring | ReturnConsumedCapacity = INDEXES, TOTAL or NONE (default) |
| Worked example | Capacity |
|---|---|
| 25 writes/s of 2.5 KB items | 75 WCU |
| 90 writes/min of 3 KB items | 5 WCU |
| 8 transactional writes/s of 1.5 KB items | 32 WCU |
| 40 strongly consistent reads/s of 9 KB items | 120 RCU |
| 40 eventually consistent reads/s of 9 KB items | 60 RCU |
| 40 transactional reads/s of 9 KB items | 240 RCU |
| Query reading 30 items of 300 bytes, strongly consistent | 3 RCU |
Capacity modes provisioned and on demand
| Topic | Current facts | Memory hook |
|---|---|---|
⚠️ On-demand (PAY_PER_REQUEST) |
Default and recommended for most workloads since the 50 % price cut of 2024-11-01; pay per request unit | Pay per bite |
Provisioned (PROVISIONED) |
RCU/WCU billed hourly + auto scaling (+ reserved capacity); for steady, predictable traffic | Rent the pipe |
| ⚠️ Switching modes | Provisioned → on-demand up to 4 times per rolling 24 h; on-demand → provisioned any time | Four in, any time out |
| New on-demand table | Sustains up to 4,000 writes/s and 12,000 reads/s | 4k writes, 12k reads |
| On-demand growth | Instantly up to 2× the previous peak; beyond 2× within 30 min may throttle | Double, then wait 30 |
| ⚠️ On-demand limits | Per-table quota 40,000 RRU and 40,000 WRU; optional OnDemandThroughput cap → ThrottlingException |
On-demand is not unlimited |
| ⚠️ Warm throughput | Shown free on every table and GSI; pre-warm with WarmThroughput (charged, cannot be lowered) |
Warm up before the race |
| Provisioned quotas | 40,000 RCU/WCU per table, 80,000 RCU/WCU per account per Region (adjustable) | |
| Capacity decreases | 4 at the start of each UTC day + 1 per hour (max 4 banked) = up to 27 per day | |
| Auto scaling | Target 20–90 % (console 70 %); acts after 2 consecutive minutes over target; each GSI needs its own policy | Scaling is slow, burst is fast |
| Burst capacity | Up to 300 s of unused provisioned capacity kept for spikes | Five minutes in the bank |
| On-demand price (us-east-1) | $0.625 per million WRU, $0.125 per million RRU (Standard class) | |
| Standard-IA table class | Cheaper storage, dearer requests; worth it when storage exceeds ~50 % of throughput cost; max 2 class changes per 30 days | Cold storage, same speed |
Throttling errors and retries
| Signal | Meaning and fix | Memory hook |
|---|---|---|
⚠️ ThrottlingReasons |
Each throttle names resource type + operation + limit type and the table or index ARN (since August 2025) | Read the reason, not the class |
…ProvisionedThroughputExceeded |
Over provisioned RCU/WCU → more capacity, auto scaling or on-demand | |
…KeyRangeThroughputExceeded |
Hot partition → better key, write sharding, DAX for reads, eventual reads, pre-warm | Hot key |
…MaxOnDemandThroughputExceeded |
Your on-demand cap was hit → raise it or set -1 | |
…AccountLimitExceeded |
Per-table on-demand quota reached → Service Quotas increase | |
Index… reasons |
GSI back-pressure throttles base-table writes → fix the GSI's capacity or key | The index pushes back |
| Throttling exception classes | ProvisionedThroughputExceededException, ThrottlingException, RequestLimitExceeded: all HTTP 400 and retryable |
|
| Batch throttling | No exception: throttled items return in UnprocessedItems / UnprocessedKeys → resend with backoff |
Check the leftovers |
ValidationException |
Item over 400 KB, type mismatch, bad expression, strongly consistent read on a GSI | |
ResourceNotFoundException |
Wrong table name or Region, or table not ACTIVE yet |
|
InternalServerError (500) |
Retry; a write may already have succeeded → read first or write idempotently | |
| Throttle metrics | ThrottledRequests (+1 per request), ReadThrottleEvents, WriteThrottleEvents, cause-specific …KeyRangeThroughputThrottleEvents and others |
|
| Contributor Insights | THROTTLED_KEYS mode (cheap enough to leave on) or ACCESSED_AND_THROTTLED_KEYS; keys shown in plaintext |
Find the hot key |
Reading data with GetItem Query and Scan
| Topic | Current facts | Memory hook |
|---|---|---|
GetItem |
One item by its full primary key; the cheapest read | Know the key, get the item |
Query |
Partition key = + optional sort key =, <, <=, >, >=, BETWEEN, begins_with; sorted by sort key |
One collection, in order |
Scan |
Reads the whole table or index, then filters; for exports and batch jobs | Scan = read everything |
| Page size | 1 MB per call, measured before the filter; continue with LastEvaluatedKey → ExclusiveStartKey |
No key, no more pages |
Limit |
Caps items evaluated before the filter, so pages can come back short | Limit counts reads, not results |
| Query filter | Cannot use key attributes; adds <>, OR, IN, contains, size |
|
ScanIndexForward=false |
Descending sort key order (newest first) | |
| Strong consistency | Reads are eventual by default; ConsistentRead=true on tables and LSIs only, at double cost; GSIs and streams are eventual only (strong read on a GSI → ValidationException) |
|
| Parallel scan | Each worker sends its own Segment + the same TotalSegments; faster, same capacity |
|
| Expression limits | 4 KB per expression, 300 operators, 100 IN operands, 255 bytes per placeholder; reserved words (Status, Name, Date, Total …) need #name placeholders |
# for names, : for values |
| CLI paging | --max-items + NextToken limit the output; --starting-token resumes; --page-size only splits calls |
Max = what you see |
| ⚠️ CLI default page size | Set per service (S3 listings 1,000); each DynamoDB call stops at 1 MB |
Local and global secondary indexes
| Feature | LSI | GSI |
|---|---|---|
| Partition key | Same as the table | Any S, N or B attribute; ⚠️ up to 4 attributes per key part |
| When created | Only in CreateTable |
Any time with UpdateTable (backfill) |
| Limit per table | 5 (hard) | 20 (default quota) |
| Read consistency | Eventual or strong | Eventual only |
| Throughput | Shares the table's capacity | Own RCU/WCU (provisioned) or the table's on-demand mode |
| Non-projected attributes | Fetched from the table at extra cost | Not available |
| Size limit | 10 GB per partition key value (item collection) | None |
- Projections are
KEYS_ONLY,INCLUDE(at most 100NonKeyAttributesper table in total) orALL. - Index write cost: a new indexed item takes 1 write, a changed index key value takes 2, an unrelated attribute change takes 0.
- A GSI without enough write capacity throttles the base table's writes; keep GSI WCU at least equal to the table's write rate.
- A sparse index leaves out every item that lacks the index key attribute.
Writing items and conditional writes
| Topic | Current facts | Memory hook |
|---|---|---|
PutItem |
Creates or fully replaces an item | Put = replace |
UpdateItem |
Changes named attributes; creates the item if missing (upsert) | Update = upsert |
| Update clauses | SET (assign, + or -, if_not_exists, list_append), REMOVE, ADD (numbers, sets), DELETE (set elements) |
|
| Condition expressions | On PutItem, UpdateItem, DeleteItem and transaction actions; never on BatchWriteItem |
Guard the write |
| Condition failure | ConditionalCheckFailedException (HTTP 400): re-read, don't retry blindly |
|
| Insert only if new | attribute_not_exists(<partition key name>) |
|
ReturnValuesOnConditionCheckFailure |
ALL_OLD returns the current item inside the exception, without RCU |
See why without reading |
ReturnValues |
Put and Delete: NONE, ALL_OLD; Update adds UPDATED_OLD, ALL_NEW, UPDATED_NEW; free |
|
| Atomic counter | SET n = n + :inc or ADD n :inc; safe under concurrency but not idempotent |
Counters may double-count |
| Optimistic locking | Version attribute + condition version = :expected, incremented in the same update; Java helpers @DynamoDBVersionAttribute (SDK 1.x mapper), VersionedRecordExtension (SDK 2.x Enhanced Client) |
Check the version, then write |
| Global tables (MREC) | Last writer wins across Regions, so optimistic locking doesn't protect cross-Region edits |
Batch operations and transactions
| Topic | Current facts | Memory hook |
|---|---|---|
BatchWriteItem |
Up to 25 puts or deletes, 16 MB, 400 KB per item; no updates, no conditions; not atomic | 25 to write |
BatchGetItem |
Up to 100 items, 16 MB; read consistency chosen per table | 100 to read |
| Partial failure | UnprocessedItems / UnprocessedKeys → resend with exponential backoff |
|
| SDK batch helpers | boto3 Table.batch_writer(), the Java Enhanced Client and DynamoDBMapper resend leftovers |
|
| ⚠️ Transaction size | 100 actions on 100 distinct items, 4 MB, one account and one Region | 100 and 4 |
| Transaction actions | Put, Update, Delete, ConditionCheck; one action per item |
|
| Transaction cost | 2× capacity, consumed even when the transaction is cancelled | |
ClientRequestToken |
Idempotent for 10 minutes; changed parameters → IdempotentParameterMismatchException |
Same token, same result |
TransactionCanceledException |
CancellationReasons in request order (ConditionalCheckFailed, TransactionConflict, ThrottlingError …); SDKs don't retry it |
|
| Transaction IAM | Per action: dynamodb:PutItem, UpdateItem, DeleteItem, GetItem, ConditionCheckItem; scope with dynamodb:EnclosingOperation |
|
| Isolation | Serializable with single-item calls; read-committed with Query, Scan, BatchGetItem |
PartiQL
| Topic | Current facts | Memory hook |
|---|---|---|
| Statements | SELECT, INSERT, UPDATE, DELETE on one table or index; no joins |
SQL look, NoSQL rules |
| Cost | A SELECT whose WHERE doesn't pin the partition key with = or IN is a full table scan |
|
| APIs | ExecuteStatement, BatchExecuteStatement (25 statements), ExecuteTransaction (100 statements) |
25 batch, 100 transaction |
| Mixing | A batch or transaction is all reads or all writes | |
INSERT |
Never overwrites: an existing key → DuplicateItemException |
|
| IAM actions | dynamodb:PartiQLSelect, PartiQLInsert, PartiQLUpdate, PartiQLDelete |
|
| Blocking scans | Deny dynamodb:PartiQLSelect when dynamodb:FullTableScan is true |
DAX and caching choices
| Topic | Current facts | Memory hook |
|---|---|---|
| What it is | Managed in-memory write-through cache in your VPC, DynamoDB API-compatible through the DAX client | Same API, microseconds |
| Item cache | GetItem / BatchGetItem results; updated by writes through DAX; default TTL 5 min |
|
| Query cache | Query / Scan results; not updated by writes; default TTL 5 min (query-ttl-millis) |
Query cache goes stale |
| Consistency | Eventual reads are cached; strongly consistent reads and TransactGetItems pass through |
Strong skips the cache |
| ⚠️ Cluster size | Developer Guide: up to 11 nodes = 1 primary + 10 read replicas (⚠️ unverified: the CreateCluster API reference still says 10); production at least 3 nodes in different AZs |
1 + 10, at least 3 |
| Scaling | Add replicas online for reads; a larger node type needs a new cluster | |
| Network | VPC only; security group allows TCP 8111 (dax://) or 9111 (TLS daxs://); Lambda functions must be attached to the VPC |
|
| Security | The cluster's service role calls DynamoDB; callers need dax:* actions; per-user LeadingKeys is not enforced |
DAX wears its own badge |
| Bypassed writes | Writes sent straight to DynamoDB leave DAX stale until TTL | |
| DAX vs ElastiCache | DAX: DynamoDB reads with no code change. ElastiCache: aggregates, multi-source data, sessions, custom logic |
DynamoDB Streams and Lambda
| Topic | Current facts | Memory hook |
|---|---|---|
| Retention and order | 24 hours; each change exactly once; ordered per item | One day, once, in order |
| View types | KEYS_ONLY, NEW_IMAGE, OLD_IMAGE, NEW_AND_OLD_IMAGES; not editable, re-create the stream |
|
| Backfill | None: only changes after enabling are captured | |
| Lambda event source mapping | Polls each shard 4 times per second, invokes synchronously; GetRecords calls not charged |
|
| Batch size | Default 100, max 10,000; batching window up to 300 s; payload at most 6 MB | |
| Starting position | TRIM_HORIZON or LATEST (LATEST can miss events while the mapping is created) |
|
| Default on error | Retries until the records expire (24 h), blocking the shard | Poison record blocks the shard |
| Error controls | MaximumRetryAttempts (0–10,000), MaximumRecordAgeInSeconds (up to 604,800), BisectBatchOnFunctionError, ReportBatchItemFailures |
|
| ⚠️ On-failure destinations | SQS queue, SNS topic or S3 bucket (only S3 receives the batch payload) | |
ParallelizationFactor |
1–10 concurrent batches per shard, order kept per partition key | |
| Filtering | FilterCriteria on eventName, Keys, NewImage, OldImage; up to 5 patterns; no numeric matching |
Filter before you pay |
| Execution role | dynamodb:DescribeStream, GetRecords, GetShardIterator, ListStreams (AWSLambdaDynamoDBExecutionRole) |
|
| Readers per shard | At most 2 on a single-Region table, 1 on a global table | |
| Kinesis Data Streams for DynamoDB | Longer retention, more consumers, Firehose; records may be out of order or duplicated | |
| ⚠️ KCL adapter | KCL 3.5.x+ with SDK for Java 2.x; KCL 1.x end of support 2026-01-30 |
Time to Live
| Topic | Current facts | Memory hook |
|---|---|---|
| Attribute | Number in Unix epoch seconds; other types and formats are ignored | Seconds, not strings |
| ⚠️ Timing | Deleted typically within a few days after expiry | Days, not seconds |
| Cost | No WCU consumed for TTL deletes in the Region where items expire | Free cleanup |
| Expired but present | Still returned by reads → filter on the TTL attribute | |
| Stream record | REMOVE with userIdentity.type Service and principalId dynamodb.amazonaws.com |
|
| Indexes | TTL deletes also remove the item's LSI and GSI entries | |
| Old timestamps | More than 5 years in the past → not deleted | |
| Enable or disable | One UpdateTimeToLive change per table per hour |
|
| ⚠️ Global tables | Replicated TTL deletes cost replicated write units in other Regions; MRSC tables don't support TTL |
Security and fine grained access control
| Topic | Current facts | Memory hook |
|---|---|---|
| App-user access | Cognito identity pool → role with dynamodb:LeadingKeys = ${cognito-identity.amazonaws.com:sub} |
Your key, your items |
dynamodb:LeadingKeys |
Partition key values of the request; use with ForAllValues:StringEquals |
|
dynamodb:Attributes |
Allowed attributes; list the keys too; pair with dynamodb:Select = SPECIFIC_ATTRIBUTES |
|
dynamodb:ReturnValues |
Restrict to NONE, UPDATED_OLD, UPDATED_NEW to hide attributes on writes |
|
| Scan in FGAC policies | Never grant it: Scan ignores leading keys |
|
| ⚠️ Resource-based policies | Tables, indexes and streams; max 20 KB; cross-account without assuming a role; Block Public Access | Policy on the table |
| Encryption at rest | Always on: AWS owned key (default), AWS managed aws/dynamodb, or a customer managed key |
Always encrypted |
| Gateway endpoint | Free, route-table based, usable only from inside the VPC | |
| ⚠️ Interface endpoint | PrivateLink (since March 2024), billed, reachable from on-premises and peered VPCs; clients use the endpoint-specific DNS name (no private DNS) | |
| Endpoint restriction | aws:SourceVpce or aws:SourceVpc condition in the table or endpoint policy |
|
| ABAC | Tag conditions aws:ResourceTag, aws:RequestTag, aws:TagKeys; indexes inherit table tags |
|
| ⚠️ Managed policy | AmazonDynamoDBFullAccess deprecated 2025-04-25 → AmazonDynamoDBFullAccess_v2 |
Serverless patterns and table operations
| Topic | Current facts | Memory hook |
|---|---|---|
| Session store | DynamoDB + TTL: reachable from every instance, self-expiring, serverless; ElastiCache: lower latency but a cluster to run; S3: too slow and costly per request for tiny objects; EBS or instance store: one instance only | Shared, serverless, self-expiring |
| Random-suffix sharding | Best write spread; reads must query all N suffixes and merge | Random spreads, reads fan out |
| Calculated-suffix sharding | Suffix from a hash of a known attribute, so one item can be read with GetItem |
Calculated = findable |
| Large objects | Store in S3, keep bucket/key + metadata in DynamoDB; no transaction spans both | Blob in S3, pointer in DynamoDB |
| Empty a table | Delete and recreate it, not Scan + DeleteItem |
Drop, don't sweep |
| ⚠️ Copy a table | Export to S3 (needs PITR, no RCU) + import from S3 into a new table (no WCU); or AWS Backup, Glue, custom code | Export, then import |
| ⚠️ PITR | Per-second restore within a 1–35 day period (RecoveryPeriodInDays); every restore creates a new table |
|
| On-demand backups | DynamoDB or AWS Backup; kept until deleted; no performance impact | |
| ⚠️ Deletion protection | DeletionProtectionEnabled blocks DeleteTable for everyone |
|
| Global tables MREC | Default; asynchronous (typically within a second), last writer wins, 99.999 % SLA | |
| ⚠️ Global tables MRSC | Exactly 3 Regions (or 2 + witness), RPO 0, strong reads in any Region; no TTL, LSIs or transactions | Three Regions, zero RPO |
| DynamoDB Local | Port 8000, --endpoint-url http://localhost:8000; throughput ignored; JAR, Docker, Maven or CloudShell |
Numbers to know
| Item | Value | Note |
|---|---|---|
| Item size | 400 KB | Attribute names included |
| Partition key / sort key length | 2,048 / 1,024 bytes | Minimum 1 byte |
| Per-partition throughput | 3,000 RCU / 1,000 WCU | Hot-key ceiling |
| Partition size | 10 GB | Also the LSI item-collection limit |
| Read / write unit size | 4 KB / 1 KB | Round each item up |
| Eventual / transactional read factor | ½ / 2 | Relative to a strongly consistent read |
| Query or Scan page | 1 MB | Measured before the filter |
| BatchWriteItem | 25 requests, 16 MB | Puts and deletes only |
| BatchGetItem | 100 items, 16 MB | |
| Transaction | 100 actions, 4 MB | ⚠️ older material: 25 items |
| Idempotency token window | 10 minutes | ClientRequestToken up to 36 characters |
| LSIs per table | 5 | Fixed, defined only at creation |
| GSIs per table | 20 | Default quota |
| Projected non-key attributes | 100 | Across all indexes of a table |
| Expression length / operators | 4 KB / 300 | IN takes up to 100 operands |
| Nesting depth | 32 levels | Lists and maps |
| Number precision | 38 digits | Sent as strings |
| Tables per Region | 2,500 | Up to 10,000 via the account team |
| Concurrent control-plane operations | 500 | Then LimitExceededException |
| ⚠️ Switches to on-demand | 4 per rolling 24 h | Back to provisioned any time |
| New on-demand table | 4,000 writes/s, 12,000 reads/s | Then 2× the previous peak instantly |
| On-demand growth window | 30 minutes | For traffic beyond 2× the previous peak |
| On-demand per-table quota | 40,000 RRU / 40,000 WRU | Adjustable |
| Provisioned quotas | 40,000 per table, 80,000 per account | RCU and WCU each, adjustable |
| Provisioned decreases | Up to 27 per day | 4 banked + 1 per hour |
| Burst capacity | 300 seconds | Of unused provisioned capacity |
| Auto scaling target | 20–90 % | Console suggests 70 % |
| On-demand price (us-east-1) | $0.625 / $0.125 per million | WRU / RRU, Standard class |
| Table-class changes | 2 per 30 days | Standard ↔ Standard-IA |
| Stream retention | 24 hours | Kinesis Data Streams for longer |
| Stream readers per shard | 2 (global tables: 1) | More readers → throttling |
| ESM batch size | 100 default, 10,000 max | Batching window up to 300 s |
| ESM parallelization factor | 1–10 | Order kept per partition key |
| ⚠️ DAX nodes | 11 = 1 primary + 10 replicas | Developer Guide; ⚠️ unverified (API reference: 10); production at least 3 |
| DAX TTL default | 5 minutes | Item cache and query cache |
| DAX ports | 8111 / 9111 | dax:// / TLS daxs:// |
| ⚠️ TTL deletion | Within a few days | Older material: 48 hours |
| ⚠️ PITR period | 1–35 days | Restores go to a new table |
| Resource-based policy size | 20 KB | Tables, indexes, streams |
| DynamoDB Local port | 8000 | --endpoint-url http://localhost:8000 |
Decision rules
- If you see a capacity calculation, think per second → round each item up → ½ for eventual or ×2 for transactional → round up.
- If you see throttling while the table has spare capacity, think hot partition or GSI back-pressure, and read
ThrottlingReasons. - If you see
Index…in a throttling reason, think fix the GSI's capacity or key, not the table's. - If you see items missing after a batch call, think
UnprocessedItems/UnprocessedKeysresent with exponential backoff. - If you see unknown or spiky traffic with LEAST operational overhead, think on-demand.
- If you see steady, predictable traffic at the lowest cost, think provisioned + auto scaling.
- If you see a known spike far above the previous peak, think pre-warm with
WarmThroughput. - If you see a need to cap on-demand spend, think
OnDemandThroughput. - If you see a rarely read table whose bill is mostly storage, think the Standard-IA table class.
- If you see "find one item by key", think
GetItem. - If you see a filter offered as a way to save RCU, think it saves nothing: use a key condition or an index.
- If you see fewer results than
Limit, thinkLimitcounts evaluated items → paginate withLastEvaluatedKey. - If you see a new access pattern on an existing table, think GSI.
- If you see an alternate sort key with strongly consistent reads at design time, think LSI.
- If you see lost updates from concurrent edits, think optimistic locking with a condition expression.
- If you see "create only if absent", think
attribute_not_exists(<partition key>). - If you see approximate counts, think atomic counter; for money or stock, think conditional update or transaction.
- If you see all-or-nothing changes across items or tables, think
TransactWriteItems+ClientRequestToken. - If you see bulk loading, think
BatchWriteItemorbatch_writer(), not transactions. - If you see SQL-style access to DynamoDB, think PartiQL with
dynamodb:PartiQL*actions. - If you see microsecond reads with minimal code change, think DAX; for aggregates, think ElastiCache.
- If you see stale
Queryresults behind DAX, think the query cache TTL. - If you see "react to new or changed items", think Streams + Lambda event source mapping with a filter.
- If you see a poison record blocking a stream, think bisect + retry limit + partial batch response + on-failure destination.
- If you see automatic, free deletion of old items, think TTL on an epoch-seconds Number.
- If you see per-user item access from a mobile app, think identity pool role +
dynamodb:LeadingKeys. - If you see cross-account table access without assuming a role, think a resource-based policy.
- If you see a private path without NAT, think gateway endpoint; from on-premises, think interface endpoint.
- If you see "copy a table without using its read capacity", think export to S3 + import from S3.
- If you see RPO 0 across Regions, think an MRSC global table.
Memory hooks
- Write 1, read 4: 1 KB per WCU, 4 KB per RCU.
- Eventual halves, transactional doubles.
- Round first, then multiply.
- Query pools its items; batches round each one.
- Filters don't refund capacity.
- Limit counts reads, not results.
- No
LastEvaluatedKey, no more pages. - 3-1-10: 3,000 RCU, 1,000 WCU and 10 GB per partition.
- Many doors, even crowds: high-cardinality partition keys.
- Local = same partition key, strong reads, born with the table.
- Global = any key, eventual only, added any time.
- The index pushes back: a starved GSI throttles table writes.
- Put replaces, Update upserts.
- Check the version, then write.
- 25 to write, 100 to read, 100 per transaction.
- Transactions pay twice, even when cancelled.
- Same token, same result for 10 minutes.
- Four in, any time out: switching to on-demand.
- Double, then wait 30: on-demand growth.
- Warm up before the race: pre-warm with
WarmThroughput. - Strong skips the DAX cache; the query cache goes stale.
- One day, once, in order: DynamoDB Streams.
- Seconds, not strings: the TTL attribute.
- Your key, your items:
dynamodb:LeadingKeys. - Blob in S3, pointer in DynamoDB.