☰ All modules Tier 1 · Serverless (DynamoDB and serverless patterns) GuideCheat sheet ‹ api-gatewaysecurity-encryption ›
Contents
  1. How Serverless (DynamoDB and serverless patterns) appears on DVA-C02
  2. 1. Tables items and primary keys
  3. 2. Read and write capacity units
  4. 3. Capacity modes provisioned and on demand
  5. 4. Throttling errors and retries
  6. 5. Reading data with GetItem Query and Scan
  7. 6. Local and global secondary indexes
  8. 7. Writing items and conditional writes
  9. 8. Batch operations and transactions
  10. 9. PartiQL
  11. 10. DAX and caching choices
  12. 11. DynamoDB Streams and Lambda
  13. 12. Time to Live
  14. 13. Security and fine grained access control
  15. 14. Serverless patterns and table operations
  16. Quick decision rules
  17. Changed vs older material

Serverless (DynamoDB and serverless patterns) — DVA-C02 Mastery Guide

  • Sources: course chapter 15 (DynamoDB), used as the syllabus only; all wording, examples and questions here are original.
  • Written 2026-10-12 · values checked against AWS docs on 2026-10-12. ⚠️ Changed: <current>. Older material may say <old>. marks a value or behaviour that differs from the course or older practice tests: learn the current value (prices and quotas are volatile). ⚠️ unverified marks a detail that AWS documentation did not confirm, or on which AWS pages disagree: never base an exam answer on it. Every change is listed in Changed vs older material; the rows you confirm are also kept in notes/current-facts.md.
  • Tier 1 (highest exam weight), bank target 40 questions. Domains: Development with AWS Services (primary), Troubleshooting and Optimization.
  • How to use it: /explain <topic> teaches from these sections (concept → exam facts → developer angle → traps → 3 check questions); /quiz dynamodb asks bank questions whose source_note links point at the ## N. headings below; /drill dynamodb fires short recall prompts from notes/dynamodb-cheat-sheet.md. Suggested loop: read a section and answer its practice questions before opening the answers → /explain what is still unclear → /quiz dynamodb → /drill dynamodb.

How Serverless (DynamoDB and serverless patterns) appears on DVA-C02

DynamoDB is the default answer whenever a scenario says "serverless", "key-value", "single-digit millisecond" or "scales without management". Questions treat it as something your code calls through the SDK, so they test what a developer decides and debugs:

Typical question shapes: a calculation with four numeric options; a symptom to diagnose (ProvisionedThroughputExceededException, ConditionalCheckFailedException, items missing after a batch, stale reads); "Which TWO…" design choices; the exact API, parameter or condition key that does the job.

Deciding constraints: LEAST operational overhead (TTL instead of a cleanup job, on-demand instead of capacity planning, DAX instead of a hand-written cache); MOST cost-effective (Query over Scan, eventually consistent reads, small projections, Standard-IA for cold tables); LOWEST latency (DAX); fewest code changes (DAX is API-compatible; a GSI instead of a new table); least privilege (item-level IAM conditions).

Domain map: Development with AWS Services → §1, §5–§9, §11–§14 · Troubleshooting and Optimization → §2, §3, §4, §6 (GSI throttling), §10.

Out of scope here (owned by other modules): IAM policy grammar and evaluation → notes/iam-guide.md; Cognito identity pools and web identity federation → notes/advanced-identity-guide.md; Lambda concurrency, scaling and async destinations in general → notes/lambda-guide.md; SDK retry modes, backoff with jitter and the credential chain → notes/cli-sdk-policies-guide.md (role credentials on EC2: notes/ec2-mastery-guide.md §1); KMS key types and policies → notes/security-encryption-guide.md; ElastiCache engines and caching strategies → notes/rds-guide.md; gateway vs interface endpoint design → notes/vpc-guide.md; CloudWatch alarms and CloudTrail → notes/monitoring-guide.md; Kinesis Data Streams and KCL → notes/sqs-sns-kinesis-guide.md; S3 event notifications → notes/s3-guide.md; table resources in templates → notes/sam-guide.md and notes/cloudformation-guide.md.

# Topic Why it is on the exam
1 Tables items and primary keys Key design decides cost, speed and throttling; data types and the 400 KB item limit
2 Read and write capacity units The classic calculation question: size rounding, consistency and transactional multipliers
3 Capacity modes provisioned and on demand Choosing the mode under a cost or traffic constraint; switching, auto scaling, warm throughput
4 Throttling errors and retries Reading the error and metric to find the real cause: hot key, GSI, quota or provisioned limit
5 Reading data with GetItem Query and Scan The cheapest correct read; filters, projections, pagination and parallel scans
6 Local and global secondary indexes New access patterns without a new table; consistency and throughput differences
7 Writing items and conditional writes Preventing lost updates: conditions, optimistic locking, atomic counters
8 Batch operations and transactions Fewer round trips vs all-or-nothing; limits, partial failures and capacity cost
9 PartiQL SQL-style access, its three APIs, limits and IAM actions
10 DAX and caching choices Microsecond reads without a rewrite, and when ElastiCache fits better
11 DynamoDB Streams and Lambda Change data capture into Lambda: view types, ordering, retries and failure handling
12 Time to Live Free automatic expiry; timing, format and Streams side effects
13 Security and fine grained access control Per-user item access, encryption, private connectivity and cross-account access
14 Serverless patterns and table operations Session store, write sharding, large objects in S3, backups, copies and global tables

1. Tables items and primary keys

Concept

Exam facts

Developer angle

Create a composite-key table and wait until it is usable:

aws dynamodb create-table --table-name Orders \
  --attribute-definitions AttributeName=CustomerId,AttributeType=S AttributeName=OrderDate,AttributeType=S \
  --key-schema AttributeName=CustomerId,KeyType=HASH AttributeName=OrderDate,KeyType=RANGE \
  --billing-mode PAY_PER_REQUEST
aws dynamodb wait table-exists --table-name Orders          # returns once the table is ACTIVE

Traps

Practice questions

  1. A developer is designing a table for a fitness app. The main screen lists one member's workouts from newest to oldest, and members can open a single workout. Traffic is spread across millions of members. Which primary key design meets these needs?

    • A. Partition key workoutType, sort key startTime
    • B. Partition key startDate, sort key memberId
    • C. Partition key memberId, sort key startTime
    • D. Partition key workoutId only, filtering on memberId when reading
  2. Writes to a user-profile table started failing with ValidationException: Item size has exceeded the maximum allowed size. The team must keep all profile data available to the application. Which TWO changes address the cause? (Select TWO.)

    • A. Move each profile's large avatar image to Amazon S3 and store only the object key in the item.
    • B. Switch the table from provisioned to on-demand capacity mode.
    • C. Add a global secondary index that projects the avatar attribute.
    • D. Shorten the long attribute names that every item repeats.
    • E. Enable DynamoDB Streams with the NEW_IMAGE view type.
Answers
  1. C. memberId has high cardinality and keeps each member's workouts in one item collection; startTime as sort key gives a newest-first Query (ScanIndexForward=false) and a direct GetItem. A concentrates traffic on a few workout types; B turns "one member's workouts" into a cross-partition search; D needs a scan with a filter because memberId is not a key.
  2. A, D. The 400 KB limit counts attribute names and values, so moving large binaries to S3 and shortening names both shrink the items. B changes billing, not item size; C copies the attribute into an index entry and leaves the base item as large as before; E only publishes changes.

2. Read and write capacity units

Concept

Exam facts

Workload Working Capacity
25 writes/s of 2.5 KB 25 × ⌈2.5⌉ = 25 × 3 75 WCU
90 writes/min of 3 KB 1.5 writes/s × 3 = 4.5 5 WCU
8 transactional writes/s of 1.5 KB 8 × 2 × 2 32 WCU
40 strongly consistent reads/s of 9 KB 40 × ⌈9/4⌉ = 40 × 3 120 RCU
Same reads, eventually consistent 120 ÷ 2 60 RCU
Same reads, transactional 120 × 2 240 RCU
12 eventually consistent reads/s of 1 KB 12 × 1 ÷ 2 6 RCU

Developer angle

Measure instead of guessing:

aws dynamodb get-item --table-name Orders \
  --key '{"CustomerId":{"S":"C-1001"},"OrderDate":{"S":"2026-10-12#A17"}}' \
  --consistent-read --return-consumed-capacity TOTAL
# ... "ConsumedCapacity": {"TableName": "Orders", "CapacityUnits": 1.0}

Traps

Practice questions

  1. An IoT backend writes 300 sensor readings per minute to a provisioned table. Each item is 2.2 KB and uses a standard PutItem. How many WCU must the table provision to sustain this rate without throttling?

    • A. 5 WCU
    • B. 15 WCU
    • C. 11 WCU
    • D. 30 WCU
  2. A table stores 7 KB product items, and an API performs 20 strongly consistent GetItem calls per second on them. Some endpoints tolerate slightly stale data, and rarely used data may move to cheaper storage. A developer must lower the read capacity this API consumes. Which TWO changes reduce the consumed RCU? (Select TWO.)

    • A. Use eventually consistent reads for the endpoints that tolerate slightly stale data.
    • B. Add a ProjectionExpression that returns only the three attributes the API displays.
    • C. Move a rarely used 4 KB description attribute to Amazon S3 so that each item drops below 4 KB.
    • D. Add a FilterExpression that discards inactive products.
    • E. Replace GetItem with TransactGetItems for consistent snapshots.
Answers
  1. B. 300 per minute = 5 writes/s; 2.2 KB rounds up to 3 KB → 5 × 3 = 15 WCU. A ignores the item size; C multiplies by 2.2 without rounding up; D doubles the result as if the writes were transactional.
  2. A, C. Eventually consistent reads halve the cost (2 RCU → 1 RCU per read of a 7 KB item); shrinking the item from 7 KB (two 4 KB blocks) to under 4 KB (one block) halves it again. B and D change what is returned, not what is read; E doubles the cost.

3. Capacity modes provisioned and on demand

Concept

Exam facts

Developer angle

# provisioned -> on-demand (at most 4 per rolling 24 h); back to PROVISIONED works any time
aws dynamodb update-table --table-name Orders --billing-mode PAY_PER_REQUEST

# cap on-demand spend: requests above the cap get ThrottlingException (-1 removes the cap)
aws dynamodb update-table --table-name Orders \
  --on-demand-throughput MaxReadRequestUnits=2000,MaxWriteRequestUnits=1000

# pre-warm before a launch (charged, cannot be decreased later)
aws dynamodb update-table --table-name Orders \
  --warm-throughput ReadUnitsPerSecond=30000,WriteUnitsPerSecond=12000

Traps

Practice questions

  1. A retailer's on-demand table peaked at about 3,000 writes per second last month. A flash sale starting at 09:00 is expected to push writes to 20,000 per second within the first minute. Which action prevents throttling with the LEAST operational overhead?

    • A. Switch the table to provisioned mode with auto scaling at a 70 % target.
    • B. Put a DynamoDB Accelerator (DAX) cluster in front of the table.
    • C. Add exponential backoff to the order service's retry logic.
    • D. Raise the table's write warm throughput before the sale starts.
  2. A provisioned table with auto scaling (target 70 %) throttles writes during bursts lasting 20–40 seconds, even though auto scaling raises capacity a few minutes later. Which TWO statements correctly explain or resolve the behaviour? (Select TWO.)

    • A. Raising the target utilization to 90 % gives the table more headroom during bursts.
    • B. Auto scaling acts only after the target has been breached for consecutive minutes, so short bursts outrun it.
    • C. Switching the table to on-demand mode lets it absorb bursts up to double its previous peak instantly.
    • D. Burst capacity is not available to tables that use auto scaling.
    • E. Adding a local secondary index spreads the writes across more partitions.
Answers
  1. D. Pre-warming raises the instantly available write rate ahead of a known event with one API call; 20,000 writes/s is far beyond double the previous peak, so on-demand alone would throttle. A still lags behind a one-minute ramp; B accelerates reads, not writes; C only retries after throttling has already happened.
  2. B, C. Target tracking needs sustained breaches and then minutes to apply, while on-demand serves up to 2× the previous peak at once. A shrinks the headroom; D is false — burst capacity still applies but runs out once the saved 300 seconds are spent; E is impossible on an existing table, and LSIs share the table's capacity anyway.

4. Throttling errors and retries

Concept

Exam facts

Error HTTP Retry? Typical cause / fix
ProvisionedThroughputExceededException 400 Yes Over the provisioned RCU/WCU of the table or a GSI, or a hot partition; the reason says which
ThrottlingException 400 Yes On-demand cap, hot partition or on-demand scaling; also control-plane calls sent too fast
RequestLimitExceeded 400 Yes Account-level throughput quota reached → request an increase
ConditionalCheckFailedException 400 No The condition evaluated to false (§7): re-read instead of resending
TransactionConflictException 400 Yes, once the transaction ends A single-item write hit an item inside an ongoing transaction
TransactionCanceledException 400 Depends Read CancellationReasons (§8); SDKs don't retry it
ItemCollectionSizeLimitExceededException 400 Yes An LSI item collection reached 10 GB (§6)
ValidationException 400 No Item over 400 KB, type mismatch, bad expression, strongly consistent read on a GSI
ResourceNotFoundException 400 No Wrong table name or Region, or the table is not ACTIVE yet
AccessDeniedException 400 No Missing IAM permission or an incorrectly signed request
InternalServerError / ServiceUnavailable 500 / 503 Yes Transient; a 500 on a write may have applied → read first, or make the write conditional or idempotent

Developer angle

import random
import time

import boto3
from botocore.config import Config

ddb = boto3.client("dynamodb", config=Config(retries={"max_attempts": 10, "mode": "standard"}))

def write_all(table, put_requests):            # put_requests: up to 25 {"PutRequest": {...}} entries
    pending, attempt = {table: put_requests}, 0
    while pending:
        response = ddb.batch_write_item(RequestItems=pending)
        pending = response.get("UnprocessedItems", {})
        if pending:                             # throttled items come back here, not as an exception
            attempt += 1
            time.sleep(random.uniform(0, min(20, 0.05 * 2 ** attempt)))

Traps

Practice questions

  1. A provisioned Orders table has 4,000 WCU and consumes about 1,500 WCU, yet clients receive ProvisionedThroughputExceededException on PutItem. The ThrottlingReasons list shows IndexWriteProvisionedThroughputExceeded with the ARN of the ByStatus global secondary index. Which change resolves the throttling with the FEWEST changes?

    • A. Increase the write capacity of the ByStatus index, or enable auto scaling on it.
    • B. Increase the base table's provisioned WCU to 8,000.
    • C. Switch the API's reads to eventually consistent mode.
    • D. Place a DynamoDB Accelerator (DAX) cluster in front of the table.
  2. A nightly job loads 2 million records into an on-demand table with BatchWriteItem. The job reports success, but about 3 % of the records are missing and no exceptions were logged. The table normally handles a few hundred writes per second. Which TWO actions should the developer take? (Select TWO.)

    • A. Check UnprocessedItems in every response and resubmit those items with exponential backoff.
    • B. Replace BatchWriteItem with TransactWriteItems so that each batch is all-or-nothing.
    • C. Enable DynamoDB Streams so that DynamoDB retries the failed writes automatically.
    • D. Switch the table to provisioned mode with a 90 % auto scaling target.
    • E. Raise the table's write warm throughput before the job, or ramp the load up gradually.
Answers
  1. A. The reason and ARN point at the GSI: an under-provisioned index back-pressures base-table writes, so the index needs capacity. B adds capacity where none is missing; C changes reads, not writes; D caches reads and does nothing for index writes.
  2. A, E. Throttled batch items come back in UnprocessedItems instead of raising an error, and jumping far above the previous peak of an on-demand table throttles unless it is pre-warmed or ramped. B doubles the capacity cost and caps each call at 100 items; C only records writes that succeeded; D at 90 % leaves even less headroom, and auto scaling lags.

5. Reading data with GetItem Query and Scan

Concept

Exam facts

Option Effect
none every page is fetched and printed
--max-items N prints at most N items plus a NextToken
--starting-token <token> resumes from that NextToken
--page-size N N items per underlying call: more calls, same output
--no-paginate one call, first page only
--limit N sends the API Limit; the output carries LastEvaluatedKey

Developer angle

# newest-first October orders of one customer, shipped only, two attributes, at most 20 printed
aws dynamodb query --table-name Orders \
  --key-condition-expression "CustomerId = :c AND begins_with(OrderDate, :m)" \
  --filter-expression "#st = :shipped" \
  --projection-expression "OrderDate, Amount" \
  --expression-attribute-names '{"#st":"Status"}' \
  --expression-attribute-values '{":c":{"S":"C-1001"},":m":{"S":"2026-10"},":shipped":{"S":"SHIPPED"}}' \
  --no-scan-index-forward --max-items 20

Traps

Practice questions

  1. A reporting Lambda function queries one customer's order history with a FilterExpression that keeps only shipped orders and with Limit set to 50. It often receives fewer than 50 orders although the customer has hundreds of shipped orders. What is the cause?

    • A. A FilterExpression cannot reference non-key attributes in a Query.
    • B. The query reads from an eventually consistent replica that lacks recent items.
    • C. Limit caps the items evaluated before the filter runs, and the response carries LastEvaluatedKey for the next page.
    • D. Query returns at most 50 items per call whenever a filter is present.
  2. A nightly job scans a 200 GB table with ConsistentRead=true to find items whose status is expired, about 1 % of the items. The job is the only workload at night, and data a few minutes old is acceptable. The developer must cut the read capacity the job consumes. Which TWO changes achieve this? (Select TWO.)

    • A. Add a FilterExpression on the status attribute so that only expired items are returned.
    • B. Write an expiredAt attribute only on expired items, create a GSI keyed on it, and scan that sparse index instead of the table.
    • C. Raise TotalSegments so that more workers scan in parallel.
    • D. Add a ProjectionExpression that returns only the key attributes.
    • E. Remove ConsistentRead=true so that the scan uses eventually consistent reads.
Answers
  1. C. Limit bounds the items read per call; the filter then drops the non-shipped orders, so a page can be short while LastEvaluatedKey says more data remains. A is false — filters work on non-key attributes; B does not describe how a table query behaves; D invents a cap — pages are bounded by Limit and 1 MB.
  2. B, E. A sparse GSI holds only the expired items, so scanning it reads about 1 % of the data, and eventually consistent reads cost half. A and D shrink the response, not the capacity consumed; C makes the scan finish sooner while reading exactly as much.

6. Local and global secondary indexes

Concept

Exam facts

LSI GSI
Partition key Same as the table Any attribute
Created Only with CreateTable; fixed for the table's life Any time; UpdateTable creates and deletes them (with a backfill)
Per table 5 (fixed) 20 (default quota)
Read consistency Eventual or strong Eventual only
Throughput The table's RCU/WCU Its own RCU/WCU (provisioned) or the table's on-demand mode
Non-projected attributes Fetched from the table (extra RCU and latency) Not available
Size constraint 10 GB item collection per partition key value None

Developer angle

Add a GSI to a live on-demand table, then query it:

aws dynamodb update-table --table-name Orders \
  --attribute-definitions AttributeName=WarehouseId,AttributeType=S AttributeName=ShipDate,AttributeType=S \
  --global-secondary-index-updates '[{"Create": {"IndexName": "ByWarehouse",
      "KeySchema": [{"AttributeName": "WarehouseId", "KeyType": "HASH"},
                    {"AttributeName": "ShipDate", "KeyType": "RANGE"}],
      "Projection": {"ProjectionType": "INCLUDE", "NonKeyAttributes": ["Amount"]}}}]'

aws dynamodb query --table-name Orders --index-name ByWarehouse \
  --key-condition-expression "WarehouseId = :w AND ShipDate BETWEEN :a AND :b" \
  --expression-attribute-values '{":w":{"S":"WH-7"},":a":{"S":"2026-10-01"},":b":{"S":"2026-10-12"}}'

Traps

Practice questions

  1. An existing production table Orders (partition key CustomerId, sort key OrderId) must now support a screen that lists one warehouse's orders sorted by ship date. The change must not interrupt the table. What should the developer do?

    • A. Add a local secondary index with partition key WarehouseId and sort key ShipDate.
    • B. Add a global secondary index with partition key WarehouseId and sort key ShipDate.
    • C. Scan the table with a FilterExpression on WarehouseId and sort the results in code.
    • D. Stream every change into a second table keyed on WarehouseId and ShipDate.
  2. A developer is designing a new Tickets table (partition key ProjectId, sort key TicketId). Support agents need a project's tickets ordered by priority, and the results must include writes made a moment earlier. Which TWO steps meet these requirements? (Select TWO.)

    • A. Define a local secondary index with sort key Priority in the CreateTable request.
    • B. Create a global secondary index on Priority after the table goes live.
    • C. Query the GSI with ConsistentRead set to true.
    • D. Query the local secondary index with ConsistentRead set to true.
    • E. Run a Scan with ScanIndexForward=false on Priority.
Answers
  1. B. A GSI can use a new partition key and can be added to a live table, which keeps serving traffic while the index backfills. A is impossible — LSIs keep the table's partition key and exist only from table creation; C reads the whole table on every request; D works but adds a pipeline and a second table to operate.
  2. A, D. An LSI keeps ProjectId as the partition key, adds Priority as an alternate sort key, and accepts strongly consistent queries. B and C fail because GSIs are eventually consistent only; E — ScanIndexForward belongs to Query, and a scan reads the whole table anyway.

7. Writing items and conditional writes

Concept

Exam facts

Developer angle

# create only if the username is free; on conflict return the existing item inside the error
aws dynamodb put-item --table-name Users \
  --item '{"username":{"S":"mira"},"createdAt":{"N":"1760256000"}}' \
  --condition-expression "attribute_not_exists(username)" \
  --return-values-on-condition-check-failure ALL_OLD

# atomic counter: no read needed, but a retried call counts twice
aws dynamodb update-item --table-name PageViews \
  --key '{"page":{"S":"/pricing"}}' \
  --update-expression "ADD hits :one" \
  --expression-attribute-values '{":one":{"N":"1"}}' \
  --return-values UPDATED_NEW

Optimistic locking with a version attribute:

import boto3

ddb = boto3.client("dynamodb")
key = {"caseId": {"S": "CASE-9"}}
seen = ddb.get_item(TableName="SupportCases", Key=key, ConsistentRead=True)["Item"]["version"]
try:
    ddb.update_item(TableName="SupportCases", Key=key,
                    UpdateExpression="SET #t = :title, #v = #v + :one",
                    ConditionExpression="#v = :seen",
                    ExpressionAttributeNames={"#t": "title", "#v": "version"},
                    ExpressionAttributeValues={":title": {"S": "Refund approved"},
                                               ":one": {"N": "1"}, ":seen": seen})
except ddb.exceptions.ConditionalCheckFailedException:
    pass            # another writer won: re-read, merge or tell the user

Traps

Practice questions

  1. Two support agents open the same case in a web app, and the second agent's save silently overwrites the first agent's changes. The team wants conflicting saves detected without holding locks and with the LEAST additional infrastructure. What should the developer implement?

    • A. Wrap every save in TransactWriteItems without a condition expression.
    • B. Read the case with ConsistentRead=true immediately before every save.
    • C. Process the table's DynamoDB stream to detect overwrites after they happen.
    • D. Keep a version number on each item and save with a condition on the expected version.
  2. A sign-up service must create a user item only if the username, which is the table's partition key, is not taken. When the name is taken, the response must include the existing user's createdAt value without another read request. Which TWO actions meet these requirements? (Select TWO.)

    • A. Call BatchWriteItem with a condition on the username.
    • B. Call PutItem with the ConditionExpression attribute_not_exists(username).
    • C. Set ReturnValuesOnConditionCheckFailure to ALL_OLD on the request.
    • D. Set ReturnValues to ALL_NEW on the PutItem request.
    • E. Query a GSI on username before writing to check whether the name exists.
Answers
  1. D. Optimistic locking with a conditional write rejects the stale save with ConditionalCheckFailedException, and the app reloads the case. A without a condition still overwrites; B narrows the window but doesn't close the race; C notices only after the data is lost.
  2. B, C. The condition makes the put fail when the key exists, and ALL_OLD on failure returns the existing item inside the exception at no read cost. A — batches accept no conditions; D — PutItem supports only NONE and ALL_OLD and returns nothing when the condition fails; E adds a read and leaves a race between the check and the write.

8. Batch operations and transactions

Concept

Exam facts

Developer angle

An order that must reserve stock, check the customer and be recorded as one unit, safe to resend after a timeout:

import uuid

import boto3
from botocore.exceptions import ClientError

ddb = boto3.client("dynamodb")
order_id = str(uuid.uuid4())   # doubles as the idempotency token: resend with the SAME value

try:
    ddb.transact_write_items(
        ClientRequestToken=order_id,
        TransactItems=[
            {"ConditionCheck": {"TableName": "Customers", "Key": {"customerId": {"S": "C-7"}},
                                "ConditionExpression": "accountStatus = :active",
                                "ExpressionAttributeValues": {":active": {"S": "ACTIVE"}}}},
            {"Update": {"TableName": "Inventory", "Key": {"sku": {"S": "SKU-42"}},
                        "UpdateExpression": "SET stock = stock - :qty",
                        "ConditionExpression": "stock >= :qty",
                        "ExpressionAttributeValues": {":qty": {"N": "2"}}}},
            {"Put": {"TableName": "Orders",
                     "Item": {"orderId": {"S": order_id}, "sku": {"S": "SKU-42"}, "qty": {"N": "2"}},
                     "ConditionExpression": "attribute_not_exists(orderId)"}},
        ],
    )
except ClientError as err:
    if err.response["Error"]["Code"] == "TransactionCanceledException":
        print([reason["Code"] for reason in err.response.get("CancellationReasons", [])])
        # for example ['None', 'ConditionalCheckFailed', 'None'] -> not enough stock
    else:
        raise

Traps

Practice questions

  1. A checkout service must decrement the stock of a product item, create an order item in a separate Orders table, and reject the order when the customer's account is suspended — either everything happens or nothing does. Client timeouts sometimes make the service send the same request twice. Which approach meets these requirements?

    • A. TransactWriteItems with a stock condition on the update, a ConditionCheck on the customer item, and the same ClientRequestToken on resend
    • B. BatchWriteItem containing the order and the new stock value, retried with exponential backoff
    • C. A GetItem on the customer followed by UpdateItem and PutItem calls, each retried on failure
    • D. TransactGetItems to read the stock and the customer, then a BatchWriteItem with the new values
  2. A feature runs 20 TransactWriteItems calls per second, and each call writes two items of 1.5 KB. Which TWO statements about the capacity this feature consumes are correct? (Select TWO.)

    • A. Cancelled transactions consume no write capacity.
    • B. Supplying a ClientRequestToken halves the capacity each transaction consumes.
    • C. Each item write consumes 4 WCU, so the feature needs 160 WCU.
    • D. One call could instead write 200 items, as long as each item is under 1 KB.
    • E. The prepare and commit writes of each item are visible in the table's CloudWatch capacity metrics.
Answers
  1. A. One transaction makes the three steps atomic, the conditions block overselling and suspended customers, and the reused token turns a resend into a no-op for 10 minutes. B is not atomic and accepts no conditions; C can leave stock decremented without an order and races with concurrent checkouts; D separates the read from the write, so nothing is atomic.
  2. C, E. 1.5 KB rounds up to 2 KB = 2 WCU, doubled for a transaction = 4 WCU; 20 calls × 2 items × 4 WCU = 160 WCU, and both underlying writes show in CloudWatch. A — cancelled transactions still consume capacity; B — tokens give idempotency, not a discount; D — the limit is 100 actions per transaction.

9. PartiQL

Concept

Exam facts

Developer angle

# keyed SELECT: runs as a Query (partition key equality + sort key condition)
aws dynamodb execute-statement \
  --statement "SELECT OrderDate, Amount FROM Orders WHERE CustomerId = ? AND begins_with(OrderDate, ?)" \
  --parameters '[{"S":"C-1001"},{"S":"2026-10"}]'

# INSERT fails with DuplicateItemException when the key already exists
aws dynamodb execute-statement \
  --statement "INSERT INTO Orders VALUE {'CustomerId': ?, 'OrderDate': ?, 'Amount': ?}" \
  --parameters '[{"S":"C-1001"},{"S":"2026-10-12#A19"},{"N":"12"}]'

# an index is addressed as "table"."index"
aws dynamodb execute-statement \
  --statement "SELECT OrderDate FROM \"Orders\".\"ByWarehouse\" WHERE WarehouseId = 'WH-7'"

aws dynamodb batch-execute-statement --statements file://reads.json             # at most 25 statements
aws dynamodb execute-transaction --transact-statements file://order-writes.json  # at most 100, all-or-nothing

Traps

Practice questions

  1. Analysts run ad hoc PartiQL SELECT statements against the Orders table from the console. A security engineer must stop statements that would read the whole table while still allowing statements that specify the partition key. Which solution follows least privilege?

    • A. Remove dynamodb:Scan from the analysts' IAM policy.
    • B. Set a maximum on-demand read throughput on the Orders table.
    • C. Allow dynamodb:PartiQLSelect and add a statement that denies it when dynamodb:FullTableScan is true.
    • D. Require dynamodb:Select to equal SPECIFIC_ATTRIBUTES in the analysts' policy.
  2. A developer is porting a data-fix script to PartiQL. The script inserts 60 new order items, and the business requires that either all 60 are inserted or none are. Which TWO statements are correct? (Select TWO.)

    • A. A single ExecuteTransaction call can hold all 60 INSERT statements and makes them all-or-nothing.
    • B. A single BatchExecuteStatement call can hold all 60 INSERT statements.
    • C. A batch or transaction may combine SELECT and INSERT statements in the same call.
    • D. If one of the keys already exists, the whole transaction is cancelled with TransactionCanceledException, and the reasons identify the failing INSERT.
    • E. The script's role needs dynamodb:PutItem, because PartiQL INSERT is authorized as PutItem.
Answers
  1. C. dynamodb:FullTableScan identifies scanning SELECTs, so an explicit deny on it blocks only those. A has no effect on PartiQL, which is authorized by dynamodb:PartiQLSelect; B limits throughput, not access; D controls the returned attributes, not scans.
  2. A, D. ExecuteTransaction accepts up to 100 statements atomically, and a duplicate key in any INSERT cancels the whole transaction with a reason for that statement. B — batches stop at 25 statements and aren't atomic; C — reads and writes can't be mixed; E — the action is dynamodb:PartiQLInsert.

10. DAX and caching choices

Concept

Exam facts

Developer angle

aws dax create-parameter-group --parameter-group-name catalog-ttl
aws dax update-parameter-group --parameter-group-name catalog-ttl \
  --parameter-name-values "ParameterName=record-ttl-millis,ParameterValue=120000" \
                          "ParameterName=query-ttl-millis,ParameterValue=60000"
aws dax create-cluster --cluster-name catalog-cache --node-type dax.r5.large \
  --replication-factor 3 --cluster-endpoint-encryption-type TLS \
  --iam-role-arn arn:aws:iam::111122223333:role/DaxCatalogServiceRole \
  --subnet-group-name catalog-private --parameter-group-name catalog-ttl
aws dax increase-replication-factor --cluster-name catalog-cache --new-replication-factor 5

Traps

Practice questions

  1. A product catalog API runs on Lambda functions in a VPC and reads a few thousand very popular items with GetItem. Read latency must drop from milliseconds to microseconds, data a few minutes old is acceptable, and the team wants the fewest code changes. Which solution meets these requirements?

    • A. Add an Amazon ElastiCache for Valkey cluster and implement lazy loading in the functions.
    • B. Create a DAX cluster in the VPC and switch the functions to the DAX client.
    • C. Switch the table to on-demand capacity mode.
    • D. Create a global secondary index for the popular items.
  2. After DAX was added, users see search results (served by Query) that stay outdated for up to 5 minutes after an item is updated through DAX, while GetItem calls through DAX return the new values at once. Which TWO statements explain or fix this? (Select TWO.)

    • A. Sending the updates directly to DynamoDB instead of through DAX would refresh the query cache.
    • B. Writes through DAX update the item cache but do not invalidate cached Query results.
    • C. Adding read replicas to the cluster shortens the time results stay stale.
    • D. Propagation to the table's GSI causes the 5-minute delay.
    • E. Lowering query-ttl-millis in a custom parameter group shortens how long query results stay cached.
Answers
  1. B. DAX returns cache hits in microseconds for eventually consistent reads and keeps the DynamoDB API, so only the client changes. A also caches but needs new cache-handling code; C changes billing, not latency; D adds another millisecond read path.
  2. B, E. The query cache is independent of the item cache and expires by TTL (5 minutes by default), so a shorter query-ttl-millis reduces the staleness. A makes things worse — writes that bypass DAX don't touch either cache; C adds read capacity, not freshness; D — GSI propagation takes a fraction of a second.

11. DynamoDB Streams and Lambda

Concept

Exam facts

ESM setting Default Range / note
BatchSize 100 up to 10,000; batch payload at most 6 MB
MaximumBatchingWindowInSeconds 0 up to 300 s
StartingPosition required TRIM_HORIZON or LATEST (LATEST can miss events while the mapping is created)
ParallelizationFactor 1 up to 10 batches per shard; order kept per partition key
MaximumRetryAttempts -1 (until the record expires) 0–10,000
MaximumRecordAgeInSeconds -1 (until the record expires) up to 604,800
BisectBatchOnFunctionError false splits a failing batch to isolate bad records
FunctionResponseTypes none ReportBatchItemFailures enables partial batch responses
FilterCriteria none up to 5 filter patterns, evaluated before invocation

Developer angle

aws dynamodb update-table --table-name Users \
  --stream-specification StreamEnabled=true,StreamViewType=NEW_AND_OLD_IMAGES
STREAM_ARN=$(aws dynamodb describe-table --table-name Users \
  --query "Table.LatestStreamArn" --output text)

aws lambda create-event-source-mapping --function-name welcome-mailer \
  --event-source-arn "$STREAM_ARN" --starting-position TRIM_HORIZON \
  --batch-size 100 --maximum-batching-window-in-seconds 5 \
  --maximum-retry-attempts 3 --maximum-record-age-in-seconds 3600 \
  --bisect-batch-on-function-error \
  --function-response-types ReportBatchItemFailures \
  --destination-config '{"OnFailure":{"Destination":"arn:aws:sqs:eu-west-1:111122223333:mailer-failures"}}' \
  --filter-criteria '{"Filters":[{"Pattern":"{\"eventName\":[\"INSERT\"]}"}]}'
def handler(event, context):                       # send_welcome() is the app's own mail code
    failures = []
    for record in event["Records"]:                # only INSERT records arrive, thanks to the filter
        try:
            send_welcome(record["dynamodb"]["NewImage"]["email"]["S"])
        except Exception:
            failures.append({"itemIdentifier": record["dynamodb"]["SequenceNumber"]})
            break                                  # stop at the first failure: Lambda retries from there
    return {"batchItemFailures": failures}

Traps

Practice questions

  1. A Lambda function processes a table's DynamoDB stream. One malformed record makes every invocation fail; the function's IteratorAge keeps growing and newer changes aren't processed. The team wants good records to keep flowing and the bad record kept for later analysis, with the LEAST effort. What should the developer configure on the event source mapping?

    • A. Raise the batch size to 10,000 so that the bad record is processed together with more good ones.
    • B. Change the starting position to LATEST and recreate the mapping.
    • C. Increase the function timeout to 15 minutes.
    • D. Enable BisectBatchOnFunctionError, set MaximumRetryAttempts to a small number, and add an SQS on-failure destination.
  2. A team wants a Lambda function to send a welcome email only when a new user item is created; the email address is an attribute of the item. The design must use the fewest function invocations and make no extra reads from the table. Which TWO steps meet these requirements? (Select TWO.)

    • A. Enable the table's stream with the NEW_IMAGE view type.
    • B. Enable the table's stream with the KEYS_ONLY view type and call GetItem in the function.
    • C. Add a filter on eventName equal to INSERT to the event source mapping.
    • D. Configure an OnSuccess destination so that the mapping invokes the function asynchronously.
    • E. Set ParallelizationFactor to 10 so that each record is processed once.
Answers
  1. D. Bisecting isolates the failing record, a small retry limit stops it from blocking the shard, and the on-failure destination keeps the batch details for analysis. A keeps failing a bigger batch; B skips unprocessed history and doesn't handle the next bad record; C can't fix a data error.
  2. A, C. NEW_IMAGE puts the email address into the record, and the INSERT filter limits invocations to new items. B adds a read per record; D — stream mappings support only on-failure destinations and always invoke synchronously; E adds concurrency, not filtering.

12. Time to Live

Concept

Exam facts

Developer angle

aws dynamodb update-time-to-live --table-name Sessions \
  --time-to-live-specification "Enabled=true,AttributeName=expiresAt"
aws dynamodb describe-time-to-live --table-name Sessions

# archive expirations only: invoke the function for TTL deletes, never for user deletes
# (STREAM_ARN = the table's LatestStreamArn, as in §11)
aws lambda create-event-source-mapping --function-name archive-expired \
  --event-source-arn "$STREAM_ARN" --starting-position TRIM_HORIZON \
  --filter-criteria '{"Filters":[{"Pattern":"{\"userIdentity\":{\"type\":[\"Service\"],\"principalId\":[\"dynamodb.amazonaws.com\"]}}"}]}'

Traps

Practice questions

  1. Session items store expiresAt as an ISO 8601 string, and TTL is enabled on expiresAt. A week later, sessions that expired days ago are still in the table. What is the most likely cause?

    • A. TTL deletes only items whose expiration attribute is a Number containing Unix epoch seconds.
    • B. TTL works only on tables that use on-demand capacity mode.
    • C. TTL requires DynamoDB Streams to be enabled on the table.
    • D. TTL deletions start 30 days after the expiration time.
  2. A compliance rule requires that order items be removed 400 days after creation and archived to Amazon S3 when they are removed. The solution must not pay for the deletes and must need minimal custom code. Which TWO actions should the developer take? (Select TWO.)

    • A. Schedule an EventBridge rule that runs a Lambda function to Scan and DeleteItem expired orders every night.
    • B. Enable point-in-time recovery so that expired orders can be restored later.
    • C. Enable TTL on an attribute that stores each order's expiry time in epoch seconds.
    • D. Enable a stream with the OLD_IMAGE view type and a Lambda mapping, filtered on the DynamoDB service identity, that writes the items to S3.
    • E. Enable a stream with the KEYS_ONLY view type and copy the keys to S3.
Answers
  1. A. TTL ignores items whose attribute isn't a Number of epoch seconds, so string timestamps never expire. B, C and D are false: TTL works in both capacity modes, needs no stream, and typically deletes within a few days.
  2. C, D. TTL deletes at no cost, and the stream's old image plus a filter on the service identity delivers exactly the expired items to an archiving function. A pays for reads and writes and adds a scheduler; B keeps restore points, not an archive; E loses the item data.

13. Security and fine grained access control

Concept

Exam facts

Developer angle

Item-level and attribute-level access for users of a Cognito identity pool (drop the Attributes, Select and ReturnValues conditions when users may see whole items):

{
  "Version": "2012-10-17",
  "Statement": [{
    "Sid": "OwnNotesSelectedAttributes",
    "Effect": "Allow",
    "Action": ["dynamodb:GetItem", "dynamodb:Query", "dynamodb:UpdateItem"],
    "Resource": "arn:aws:dynamodb:eu-west-1:111122223333:table/UserNotes",
    "Condition": {
      "ForAllValues:StringEquals": {
        "dynamodb:LeadingKeys": ["${cognito-identity.amazonaws.com:sub}"],
        "dynamodb:Attributes": ["userId", "noteId", "title", "body", "updatedAt"]
      },
      "StringEqualsIfExists": {
        "dynamodb:Select": "SPECIFIC_ATTRIBUTES",
        "dynamodb:ReturnValues": ["NONE", "UPDATED_OLD", "UPDATED_NEW"]
      }
    }
  }]
}

Traps

Practice questions

  1. A mobile app lets signed-in users read and write only their own items in the UserNotes table, whose partition key holds the user's Amazon Cognito identity ID. The app calls DynamoDB directly. Which solution is MOST secure?

    • A. Embed the access keys of an IAM user with DynamoDB permissions in the app and filter items by user ID in the app code.
    • B. Put the table behind an API Gateway API key that every app installation sends.
    • C. Give the Cognito identity pool's role a policy that allows the item actions when dynamodb:LeadingKeys equals ${cognito-identity.amazonaws.com:sub}.
    • D. Grant the identity pool's role dynamodb:Scan with a dynamodb:Attributes condition on the user ID attribute.
  2. A Lambda function runs in private subnets with no NAT gateway and must read a DynamoDB table in the same Region. A security policy requires that the table accept requests only when they arrive through the VPC endpoint the team creates. Which TWO actions meet these requirements? (Select TWO.)

    • A. Create a gateway VPC endpoint for DynamoDB and associate it with the subnets' route tables.
    • B. Attach a resource-based policy to the table that denies requests whose aws:SourceVpce is not the endpoint's ID.
    • C. Add a NAT gateway so that the function can reach the public DynamoDB endpoint.
    • D. Put a DAX cluster in the subnets and route all reads through it.
    • E. Add a dynamodb:LeadingKeys condition to the function's execution role.
Answers
  1. C. Temporary identity-pool credentials plus a LeadingKeys condition bound to the caller's identity ID enforce per-user item access in IAM. A ships long-term secrets and trusts the client; B identifies app installations, not users; D — Scan ignores leading keys, so every user could read all notes.
  2. A, B. The gateway endpoint gives a private route without NAT, and the table's resource-based policy enforces that endpoint with aws:SourceVpce. C adds a public path and cost; D caches reads but doesn't restrict the table; E scopes items, not network paths.

14. Serverless patterns and table operations

Concept

Option for shared session state Fit
DynamoDB + TTL Serverless key-value store reachable from every instance and Lambda function; TTL ages sessions out (§12); nothing to size in on-demand mode
ElastiCache (Valkey, Redis OSS) In-memory, so lower latency, but a cluster you size and operate (notes/rds-guide.md §10)
Amazon S3 Per-request latency and cost don't suit tiny objects rewritten on every request
Amazon EFS A file system every client must mount — clumsy for many small key lookups
EBS volume or instance store Attached to one instance, so other instances can't see the session

Exam facts

Developer angle

Calculated-suffix sharding for gate check-ins at a sold-out event:

import zlib

import boto3

SHARDS = 10
checkins = boto3.resource("dynamodb").Table("CheckIns")   # key: pk (partition) + ticketId (sort)

def shard_key(event_id, ticket_id):
    return f"{event_id}#{zlib.crc32(ticket_id.encode()) % SHARDS}"   # same ticket, same shard

def check_in(event_id, ticket_id, gate):
    checkins.put_item(Item={"pk": shard_key(event_id, ticket_id), "ticketId": ticket_id, "gate": gate})
aws dynamodb update-table --table-name Orders --deletion-protection-enabled
aws dynamodb update-continuous-backups --table-name Orders \
  --point-in-time-recovery-specification PointInTimeRecoveryEnabled=true,RecoveryPeriodInDays=14
aws dynamodb restore-table-to-point-in-time --source-table-name Orders \
  --target-table-name Orders-restored --use-latest-restorable-time
aws dynamodb export-table-to-point-in-time \
  --table-arn arn:aws:dynamodb:eu-west-1:111122223333:table/Orders \
  --s3-bucket orders-exports-444455556666 --s3-bucket-owner 444455556666 \
  --export-format DYNAMODB_JSON
aws dynamodb update-table --table-name Orders \
  --replica-updates '[{"Create": {"RegionName": "us-east-1"}}]'

Traps

Practice questions

  1. A ticketing app writes one item per gate check-in, with the event ID as the partition key and the check-in timestamp as the sort key. During a sold-out concert, writes are throttled with TableWriteKeyRangeThroughputExceeded although the table's provisioned WCU is far from used. A dashboard reads per-event totals every few seconds. Which design removes the throttling?

    • A. Create a global secondary index with the event ID as its partition key.
    • B. Append a suffix computed from a hash of the ticket ID to the partition key, and add up the N shards for the dashboard.
    • C. Put a DAX cluster in front of the table.
    • D. Raise the table's provisioned WCU.
  2. Every week, testers need a fresh copy of a 500 GB production table in a separate test account. The copy must not consume the production table's read capacity, and the team wants the LEAST operational overhead. Which TWO steps meet these requirements? (Select TWO.)

    • A. Run a parallel Scan from an EC2 instance and write the items into the test account with BatchWriteItem.
    • B. Enable DynamoDB Streams and a Lambda function that replays every change into the test account.
    • C. Give the testers DAX access to the production table instead of a copy.
    • D. With PITR enabled, export the table to an S3 bucket owned by the test account.
    • E. In the test account, import the exported data from S3 into a new table.
Answers
  1. B. The reason says one key range is hot: sharding spreads the event's writes over N partition key values and therefore over more partitions, and the dashboard sums the N shards. A — the GSI has the same hot key and back-pressures the table; C accelerates reads only; D adds table capacity, but a single key value stays capped by the per-partition limit.
  2. D, E. Export to S3 reads from PITR data, consumes no RCU and can target another account's bucket; import from S3 builds a new table without consuming write capacity. A and B consume production capacity and add code to run; C produces no copy and exposes production data.

Quick decision rules

Keys, capacity and throttling (§1–§4)

Reads, indexes and writes (§5–§9)

Caching, streams, TTL, security and operations (§10–§14)

Changed vs older material

Learn the Current column; older practice material may still show the Older material may say value. The four DynamoDB rows already in notes/current-facts.md (switching, pricing, warm throughput, on-demand initial throughput) were re-checked on 2026-10-12; the other rows join it once you confirm them.

Topic Older material may say Current (verified 2026-10-12) Source
§1 · Partitions and capacity split Partitions = ceil(max(RCU/3,000 + WCU/1,000, size/10 GB)), capacity divided equally and fixed No published formula; partitions managed automatically; adaptive capacity (instant, free) and hot-item isolation; per partition 3,000 RCU / 1,000 WCU and 10 GB AWS docs
§3 · Capacity mode switching One capacity-mode change per table per day Provisioned → on-demand up to 4 times per rolling 24 h (since August 2025); on-demand → provisioned any time AWS docs
§3 · On-demand price and positioning About 2.5× provisioned; only for unknown or spiky workloads Price cut 50 % effective 2024-11-01 (global-table replicated writes −67 % on-demand, −33 % provisioned); default and recommended for most workloads; us-east-1 Standard $0.625 per million WRU, $0.125 per million RRU What's New
§3 · On-demand throttling Unlimited capacity, never throttles Per-table quota 40,000 RRU / 40,000 WRU (adjustable); optional OnDemandThroughput cap (May 2024); more than 2× the previous peak within 30 min may throttle; partition limits apply AWS docs
§3 · Pre-warming Provision high capacity temporarily, then switch to on-demand Warm throughput visible for free on every table and GSI (2024-11-13); pre-warm with WarmThroughput (charged, cannot be decreased) in either mode AWS docs
§4 · Throttling diagnostics Only ProvisionedThroughputExceededException, no detail ThrottlingReasons (reason + resource ARN) on ProvisionedThroughputExceededException, ThrottlingException, RequestLimitExceeded; 16 cause-specific metrics; Contributor Insights throttled-keys mode (August 2025) AWS docs
§5 · AWS CLI --page-size default 1,000 items for every command Set per service (S3 1,000); each DynamoDB call bounded by 1 MB; --page-size changes only the number of calls AWS docs
§6 · GSI key schema One partition-key attribute + one optional sort-key attribute; concatenate values into synthetic keys Multi-attribute keys: up to 4 partition-key and up to 4 sort-key attributes AWS docs
§6 · GSI throughput settings Every GSI must be provisioned with its own RCU and WCU GSIs inherit the table's capacity mode: own RCU/WCU only on provisioned tables (optional OnDemandThroughput cap on on-demand tables) AWS docs
§8 · Transaction size 25 items per transaction 100 actions on 100 distinct items, 4 MB aggregate AWS docs
§10 · DAX cluster size Up to 10 nodes per cluster Developer Guide: up to 11 nodes (1 primary + up to 10 read replicas); ⚠️ unverified — the CreateCluster API reference still says ReplicationFactor ≤ 10 AWS docs
§11 · Stream ESM on-failure destinations SQS queue or SNS topic only SQS queue, SNS topic or S3 bucket (S3 also receives the batch payload) AWS docs
§11 · KCL consumers of DynamoDB Streams Kinesis Adapter with KCL 1.x and SDK for Java 1.x Kinesis Adapter with KCL 3.5.x+ and SDK for Java 2.x; KCL 1.x end of support 2026-01-30 AWS docs
§12 · TTL deletion delay Within 48 hours of expiry Typically within a few days of expiry; expired items stay readable until deleted AWS docs
§12 · TTL delete cost on global tables TTL deletes never cost anything Free in the Region where the item expires; replicated deletes consume replicated write units in the other replica Regions AWS docs
§13 · Cross-account access Requires assuming a role in the table's account Resource-based policies on tables, indexes and streams (March 2024), max 20 KB, with Block Public Access AWS docs
§13 · Private connectivity Gateway endpoints only Gateway endpoints (free) or interface endpoints via PrivateLink (March 2024; Streams March 2025), reachable from on-premises AWS docs
§13 · Full-access managed policy Attach AmazonDynamoDBFullAccess Deprecated 2025-04-25; replaced by the narrower AmazonDynamoDBFullAccess_v2 Document history
§14 · PITR recovery period Fixed 35 days Configurable 1–35 days (RecoveryPeriodInDays, January 2025); same price whatever the period AWS docs
§14 · Global table consistency Always eventually consistent between Regions (last writer wins) MREC by default; MRSC option (June 2025): 3 Regions, RPO 0, strongly consistent reads in any Region, no TTL, LSIs or transactions AWS docs
§14 · Protecting a table from deletion Only an IAM deny on dynamodb:DeleteTable Deletion protection (DeletionProtectionEnabled, March 2023) What's New
§14 · Copying a table AWS Backup, AWS Glue or a Scan + write script Also export to S3 (needs PITR, no RCU, filtered exports since October 2026) and import from S3 into a new table (no WCU) AWS docs

Re-checked and unchanged on 2026-10-12: new on-demand tables sustain up to 4,000 writes/s and 12,000 reads/s and instantly absorb up to double their previous peak (AWS docs).