
Amazon DynamoDBAuthorCloudBrum editorial teamLast reviewedReading time~12 minLevelBeginner to advanced
Amazon Web Services · Databases · Serverless key-value and document database
DynamoDB is the AWS database you pick when lookups by key must stay fast however big the table gets. You decide up front which questions the application will ask, choose a partition key to match, and AWS spreads the data over as many servers as it takes. There is no server to size or patch, and also no join and no ad hoc query, so the design work moves to the start of the project. When a DynamoDB bill surprises someone, the cause is usually an index nobody needed, a scan inside a loop, or one hot key.
On this page (17 sections)
Mind map: Amazon DynamoDB at a glance
Free to share. The downloaded image includes the CloudBrum link.
Key features (summary)
- Fast at any sizeA read or write by key returns in single-digit milliseconds whether the table holds a thousand items or billions. DynamoDB splits data by partition key and adds partitions as the table grows, so you never resize anything.
- Keys decide everythingEach item has a partition key and, optionally, a sort key. A query names one partition key value and can narrow by sort key, which is why the keys come from your access patterns and not from your entities.
- Secondary indexesA global secondary index (GSI) gives the same data another key, so a second question such as "orders by status" is also a cheap query. Every index is a copy that you pay to write and to store.
- Two ways to pay for capacityOn-demand charges per request and needs no planning. Provisioned lets you set read and write capacity, with auto scaling to follow the load, and costs less when traffic is steady and predictable.
- Conditions and transactionsA conditional write succeeds only if the item is in the state you expect. TransactWriteItems and TransactGetItems group up to 100 actions, across tables, all or nothing, at double the capacity cost.
- Streams and time to liveA stream records item changes for 24 hours for Lambda or EventBridge Pipes to read. Time to live (TTL) removes items after a timestamp that you store, in the background and without a write charge.
- Backups and recoveryPoint-in-time recovery restores a table to any second in the last 1 to 35 days, into a new table. On-demand backups and AWS Backup keep copies for as long as you need them.
- Global tablesReplicate a table to other Regions and write in any of them. The default is eventual consistency between Regions; multi-Region strong consistency, generally available since June 2025, gives a recovery point of zero in return for slower cross-Region writes.
Basic concepts
- Item
- One record, a set of attributes. An item can be up to 400 KB, and two items in a table don’t have to have the same attributes.
- Partition key
- The attribute DynamoDB hashes to decide where an item lives. It is the one value every Query must name, so it should have many different values spread evenly across your traffic.
- Sort key
- An optional second part of the primary key. Items with the same partition key are stored in sort key order, which is how a query can ask for a range, such as the last ten orders.
- Query and Scan
- A Query reads one partition key value, and is fast and cheap. A Scan reads the whole table or index, and costs the full size of what it touches even if a filter drops most of it.
- Global secondary index (GSI)
- An index with its own partition and sort key. You can add it at any time, it has its own capacity, and reads from it are eventually consistent.
- Local secondary index (LSI)
- An index that shares the table’s partition key but has another sort key. It must be created together with the table, and it limits each partition key value to 10 GB.
- Read and write unit
- The measure of capacity. One write unit writes up to 1 KB, and one read unit reads up to 4 KB with strong consistency. An eventually consistent read costs half, and a transactional read or write costs double.
- On-demand and provisioned
- The two capacity modes. On-demand bills each request. Provisioned bills the capacity you set per hour, used or not.
- Conditional write
- A write that carries a condition, such as attribute_not_exists(orderId). When the condition is false the write is rejected with ConditionalCheckFailedException, which is how you build idempotent writes.
- Stream
- An ordered log of item changes that keeps records for 24 hours. A consumer such as Lambda reads it to react to changes or to copy data elsewhere.
- Time to live (TTL)
- A number attribute that holds an expiry time in epoch seconds. DynamoDB deletes expired items in the background, usually within a few days of the timestamp.
- DAX
- DynamoDB Accelerator, a cache cluster that sits in front of a table and serves repeated reads in microseconds.
- Global table
- A table that DynamoDB replicates across Regions. Every replica accepts writes, and you choose between eventual consistency and multi-Region strong consistency.
How to create & configure it
Create a table, an index and safe defaults with the AWS CLI
- List the questions firstWrite down every way the application reads data: orders of one customer, open orders by status, one order by ID. Each question becomes a key or an index. Do this before you touch the console.
- Choose a partition key that spreadsPick an attribute with many values and even traffic, such as a customer or device ID. A key like status or a date sends most requests to a handful of partitions.
- Create the table on-demandStart with on-demand so there is no capacity to guess. Switch to provisioned later, once the traffic pattern is clear and steady.
- Add only the indexes you needEach index doubles as a second table to write and store. Project just the attributes the query returns, not all of them.
- Write with conditionsUse attribute_not_exists for inserts and a status check for updates. A retried request then can’t overwrite newer data or create a duplicate.
- Query by key, never scanUse Query with a key condition. Reserved words such as status and name need a placeholder in ExpressionAttributeNames.
- Turn on recovery and delete protectionEnable point-in-time recovery and deletion protection before the first real data arrives. Both are cheap, and you can’t add the recovery history afterwards.
- Set time to live for temporary dataStore an expiry timestamp in a number attribute for sessions, carts and tokens, and let DynamoDB do the cleanup.
- Watch for throttlingThrottledRequests and ConsumedReadCapacityUnits in CloudWatch tell you about hot keys and capacity limits before a customer does.
Tip: a local secondary index can only be created with the table, and a table’s keys can’t be changed later. If you got the keys wrong, the fix is a new table and a copy of the data. See the code references for the same setup as Terraform.
Common issues after configuration
| Symptom | Likely cause | What to check / fix |
|---|---|---|
| Requests are throttled | One partition key value gets far more traffic than the rest (a hot key), a provisioned table is set too low, or on-demand traffic jumped well above the table’s recent peak | Look at ThrottledRequests by table and index. Spread the load with a better key or a suffix, raise provisioned capacity, or let the table warm up before a launch. |
| The provided key element does not match the schema | A key attribute is missing, has the wrong name or the wrong type (a number sent as a string) | Compare the request with describe-table. The keys must match name and type exactly. |
| ValidationException: item size exceeds 400 KB | A single item grew past the limit, often through a list that keeps growing | Split the data into several items with a sort key, or keep the large part in S3 and store the object key. |
| A query returns nothing for an item that exists | The key is case-sensitive, the query hit the wrong index, or the read was eventually consistent and ran straight after the write | Check the exact key value, name the index, and use a strongly consistent read on the table when you need your own write back. Indexes are always eventually consistent. |
| A scan is slow and expensive | There is no key condition, so every item is read before the filter drops most of them | Add an index for the question you are asking, and use Query. Keep Scan for exports and one-off checks. |
| ConditionalCheckFailedException | The condition was false: the item exists, or its status isn’t what the update expected | This is the guard working. Handle it as a normal result, and read the item again if you need to decide what to do next. |
| TransactionCanceledException | One action’s condition failed, an item was in another transaction, or capacity ran out | Read CancellationReasons, which lists a reason per action in order, and retry only when the reason is a conflict or throttling. |
| An index shows old data | Global secondary indexes are updated after the table write, usually within a fraction of a second but not at the same moment | Read from the table when freshness matters, or design the flow so a short delay doesn’t matter. |
| Expired items still appear | TTL deletion is a background job, and the attribute must be a number in epoch seconds | Filter on the expiry attribute in your queries, and check that the value is seconds, not milliseconds. |
| The bill is higher than expected | Indexes that project every attribute, repeated scans, large items, strongly consistent reads and transactions, or replicated writes in global tables | Break the bill down by table and index, project fewer attributes, replace scans with queries, and compare on-demand with provisioned for the steady tables. |
Use cases: when and where to use it
Good fit
- Applications that read and write by key at high volume, such as carts, sessions, profiles and device state
- Workloads with traffic that swings from almost nothing to very large, where on-demand capacity fits
- Serverless back ends built with Lambda and API Gateway, since there are no connections to manage
- Gaming, ad tech and IoT data that needs single-digit-millisecond reads
- Systems that need a change stream to drive other work, or to replicate to analytics
- Multi-Region applications that need writes in more than one Region
Consider something else
- Joins, ad hoc SQL and reporting → Amazon RDS or Amazon Aurora
- Analytics over lots of data → export to S3 and query it with Amazon Athena
- Free-text search and aggregations → Amazon OpenSearch Service
- A cache with eviction rules → Amazon ElastiCache (or DAX in front of a DynamoDB table)
- Cassandra-compatible wide-column workloads → Amazon Keyspaces
- The same job on other clouds → compare Azure Cosmos DB and Firestore
Pros: why consider it?
Why teams choose it
- Nothing to patch, size or fail over: AWS runs the servers
- Steady, low latency for key-based reads and writes at any table size
- On-demand mode removes capacity planning
- Backups, point-in-time recovery, streams and global tables are built in
- Works naturally with Lambda, with no connection pools
- Fine-grained IAM control down to the item and attribute
Trade-offs to weigh
- Queries must follow the keys and indexes you designed, so new questions can mean new indexes or a new table
- No joins, no ad hoc queries and limited aggregation
- Changing the keys of an existing table means a migration
- A hot key can throttle one partition while the table as a whole looks quiet
- Costs follow requests, so scans, indexes and transactions add up
- Item size is capped at 400 KB, and the data model is unlike SQL, which takes time to learn
Common threats, vulnerabilities & risks
| Risk | Severity | Why it matters | Mitigation |
|---|---|---|---|
| No point-in-time recovery | High | A bad deployment or a deleted attribute can’t be undone, and an on-demand backup only holds the moment it was taken. | Enable point-in-time recovery on every table that holds real data, and test a restore once a quarter. |
| Tables open to the whole account | High | A broad dynamodb:* permission lets one compromised role read or delete every table. | Give each workload a role with the actions and the table ARNs it needs, and use condition keys such as dynamodb:LeadingKeys for per-user data. |
| Deletion without protection | High | A delete-table from a script or a wrong console click removes the data and its history. | Turn on deletion protection, and restrict dynamodb:DeleteTable to a small group. |
| A hot partition key | Medium | Most traffic lands on a few key values, so those partitions throttle while others sit idle. | Pick keys with high cardinality, add a suffix or shard number for very busy keys, and use Contributor Insights to find the busy ones. |
| Scans in production paths | Medium | A scan inside a request handler reads the whole table and slows down and costs more as the data grows. | Replace it with a query on a key or an index, and block scans through IAM for the application role. |
| Unbounded item growth | Medium | A list attribute that keeps growing hits the 400 KB limit, and each update is billed for the size of the whole item. | Store each entry as its own item under the same partition key, and cap or archive old ones. |
| Indexes that project everything | Medium | Every attribute copied to an index is paid for on each write and again in storage. | Project only the keys and the attributes the query returns, and delete indexes nobody reads. |
| Sensitive data without a key policy | Low–Med | The default encryption uses an AWS owned key, which can’t show who used it. | Use a customer managed KMS key for regulated data, and watch its use in CloudTrail. |
| Streams without a failure plan | Low–Med | A consumer that keeps failing can fall behind, and records are gone after 24 hours. | Alarm on iterator age, add a failure destination, and keep consumers idempotent. |
Performance optimisation
- Choose a partition key with many values and an even spread of traffic, so no partition becomes the bottleneck.
- Model for your queries: put the items you read together under one partition key, and read them with a single Query.
- Use BatchGetItem and batch writes for many items, and retry the unprocessed ones with exponential backoff and jitter.
- Keep items small. Large items cost more units per request, so store big blobs in S3 and keep the key.
- Use eventually consistent reads unless the code truly needs its own write back, since they use half the capacity.
- Add DAX for read-heavy, repeated lookups that need microsecond answers, and measure the hit rate before you pay for it.
- Use projection expressions to return only the attributes you need, which cuts the data sent, though not the capacity used.
- Add a random suffix to the keys of a very hot item, and read all the suffixes to combine the result.
Reduce monthly cost
FinOps is the habit of managing cloud spend together with engineering. These are the FinOps checks that matter most for Amazon DynamoDB.
- Compare on-demand and provisioned for each table. Steady, predictable tables are usually cheaper provisioned with auto scaling.
- Keep infrequently read tables in Standard-IA, which has lower storage and higher request prices.
- Project fewer attributes into indexes, and delete indexes that no query uses.
- Replace scans with queries, since a scan pays for every item it touches, not only the ones it returns.
- Use eventually consistent reads where the code allows, at half the cost of strong ones.
- Set TTL on sessions, logs and temporary data, because deleting expired items through TTL has no write charge.
- Compress or trim large attributes, and move large payloads to S3.
- Limit global table replicas to the Regions you need, since each replica pays for replicated writes.
- Review backup and PITR storage and delete on-demand backups you no longer need.
- Tag tables by team and put a budget alert on DynamoDB spend, so a runaway job shows up the same day.
Figures here come from AWS's pricing page and published guides, read in October 2026. Prices differ by Region and sources disagree on some rates, so confirm on the live page (see Pricing).
Security optimisation
- Give each workload an IAM role with only the table and index ARNs and actions it needs, not dynamodb: on .
- Use condition keys such as dynamodb:LeadingKeys and dynamodb:Attributes to limit a user to their own items.
- Use a customer managed KMS key for sensitive tables, and review who may use it. Encryption at rest is always on.
- Reach DynamoDB through a gateway VPC endpoint, with an endpoint policy that names the tables, so traffic stays off the internet.
- Add a resource-based policy to block access from outside your organisation or network.
- Turn on deletion protection and point-in-time recovery for production tables.
- Record API calls with CloudTrail, including data events for tables that need an audit of reads and writes.
- Keep secrets and card numbers out of items. Store a token or a reference, and keep the secret in Secrets Manager.
- Alert on DeleteTable, UpdateContinuousBackups and policy changes.
- Review IAM Access Analyzer findings for tables shared with other accounts.
Governance & compliance
Guardrails
- A shared Terraform module for tables that always sets point-in-time recovery, deletion protection, a KMS key and tags
- A service control policy that blocks dynamodb:DeleteTable and dynamodb:DeleteBackup outside a break-glass role
- Naming rules for tables and key attributes, with the access patterns documented next to the table definition
- A review step for new global secondary indexes, with the query that needs each one
Continuous checks (AWS Config, Security Hub and your own scripts)
- A scheduled script that lists tables without point-in-time recovery, deletion protection or time to live where it is expected (the C# tab does this)
- AWS Config rules and Security Hub controls for DynamoDB backups and encryption, where your standard includes them
- Alarms on ThrottledRequests, SystemErrors and stream iterator age
- A CloudTrail alert for table deletion and policy changes
- A monthly report of indexes with no reads
AWS CloudTrail records who created, changed or deleted tables, AWS Config keeps the configuration history, AWS Backup can hold copies under a policy, and AWS Artifact holds compliance reports. AWS runs the service, replicates the data across Availability Zones and encrypts it at rest. The key design, who may read which items, how long backups last and what is stored in the first place are yours.
Reduce carbon footprint
- Use on-demand or well-tuned auto scaling, so you don’t hold capacity that nobody uses.
- Replace scans with queries, which read far less data for the same answer.
- Delete unused indexes, old backups and expired data with TTL.
- Limit global table replicas to the Regions your users need.
- If data rules and latency allow, keep the table in a Region whose power grid is cleaner.
- The AWS carbon tool reports per account and does not list DynamoDB on its own, so quote no DynamoDB figure.
Pricing
Purchase options
On-demand Per read and write request
About $0.625 per million write units and $0.125 per million read units in US East (N. Virginia), Standard class. A write unit covers 1 KB and a strongly consistent read unit 4 KB. Eventually consistent reads cost half, and transactions cost double.
Provisioned Per capacity unit per hour
You pay for the read and write capacity you set, used or not, with auto scaling to follow the load and reserved capacity for steady tables.
Storage About $0.25 per GB-month
The first 25 GB are free. Standard table class. Standard-IA lists lower storage (about $0.10 per GB-month) and higher request prices, for tables that are rarely read.
Extras Backups, streams, global tables, DAX
Point-in-time recovery and on-demand backups by GB, stream reads above the free allowance, replicated writes in every global table Region, and DAX nodes by the hour.
What you actually pay for
- Read and write request units, or provisioned capacity units per hour
- Stored data, including indexes
- Point-in-time recovery and on-demand backup storage
- Replicated writes for each global table replica
- DAX nodes, stream reads above the free allowance, and data transfer between Regions
AWS lists an always-free allowance of 25 GB of storage and 25 provisioned read and write capacity units, and rates differ by Region. See the official Amazon DynamoDB pricing page and the AWS Pricing Calculator.
Important code references
An orders application: an on-demand Orders table keyed by customer and order, an index for open orders by status, a Stock table, time to live, point-in-time recovery, deletion protection and a stream. The CLI tab builds it, writes with a condition, queries the table and the index, and places an order and reduces the stock in one transaction. Terraform describes the same table; the Python tab shows an insert that is safe to retry, a paged query and the transaction; and the C# tab audits every table in the Region for missing recovery, protection and wasteful indexes. Replace the Region and names with your own.
# Placeholders: replace the Region with your own. The table and attribute names are examples.
REGION=ap-south-1
TABLE=Orders
# 1. The orders table. Reading "all orders of one customer" is one Query on customerId, newest or oldest first on orderId.
# On-demand billing has no capacity to plan, and deletion protection blocks an accidental delete-table.
# The index answers a second question (open orders by status) and copies only the total, not the whole item.
aws dynamodb create-table --region $REGION --table-name $TABLE \
--attribute-definitions AttributeName=customerId,AttributeType=S AttributeName=orderId,AttributeType=S AttributeName=status,AttributeType=S AttributeName=createdAt,AttributeType=S \
--key-schema AttributeName=customerId,KeyType=HASH AttributeName=orderId,KeyType=RANGE \
--billing-mode PAY_PER_REQUEST --deletion-protection-enabled \
--global-secondary-indexes 'IndexName=by-status,KeySchema=[{AttributeName=status,KeyType=HASH},{AttributeName=createdAt,KeyType=RANGE}],Projection={ProjectionType=INCLUDE,NonKeyAttributes=[total]}' \
--tags Key=team,Value=orders
aws dynamodb wait table-exists --region $REGION --table-name $TABLE
# 2. A second small table for stock levels, used in the transaction below.
aws dynamodb create-table --region $REGION --table-name Stock \
--attribute-definitions AttributeName=sku,AttributeType=S --key-schema AttributeName=sku,KeyType=HASH --billing-mode PAY_PER_REQUEST
aws dynamodb wait table-exists --region $REGION --table-name Stock
aws dynamodb put-item --region $REGION --table-name Stock --item '{"sku": {"S": "sku-9"}, "onHand": {"N": "5"}}'
# 3. Let DynamoDB delete expired items itself, and keep 35 days of recovery history.
aws dynamodb update-time-to-live --region $REGION --table-name $TABLE --time-to-live-specification Enabled=true,AttributeName=expiresAt
aws dynamodb update-continuous-backups --region $REGION --table-name $TABLE \
--point-in-time-recovery-specification PointInTimeRecoveryEnabled=true,RecoveryPeriodInDays=35
# 4. Write an order only if it does not exist yet. Run it twice: the second call is refused, which is what makes a retry safe.
cat > order.json <<JSON
{"customerId": {"S": "c-100"}, "orderId": {"S": "o-0001"}, "status": {"S": "PLACED"}, "createdAt": {"S": "2026-11-02T09:30:00Z"},
"total": {"N": "2499"}, "expiresAt": {"N": "1796000000"}}
JSON
aws dynamodb put-item --region $REGION --table-name $TABLE --item file://order.json --condition-expression "attribute_not_exists(orderId)"
aws dynamodb put-item --region $REGION --table-name $TABLE --item file://order.json --condition-expression "attribute_not_exists(orderId)" \
|| echo "Refused, as expected: the order already exists."
# 5. Query by key. This reads one customer's orders only, and --return-consumed-capacity shows what it cost.
aws dynamodb query --region $REGION --table-name $TABLE --key-condition-expression "customerId = :c" \
--expression-attribute-values '{":c": {"S": "c-100"}}' --return-consumed-capacity TOTAL
# 6. Query the index. "status" is a reserved word in DynamoDB, so it goes through a placeholder name.
aws dynamodb query --region $REGION --table-name $TABLE --index-name by-status --key-condition-expression "#s = :s" \
--expression-attribute-names '{"#s": "status"}' --expression-attribute-values '{":s": {"S": "PLACED"}}'
# 7. Move the order to SHIPPED only while it is still PLACED, so two workers can't both ship it.
aws dynamodb update-item --region $REGION --table-name $TABLE --key '{"customerId": {"S": "c-100"}, "orderId": {"S": "o-0001"}}' \
--update-expression "SET #s = :shipped" --condition-expression "#s = :placed" \
--expression-attribute-names '{"#s": "status"}' --expression-attribute-values '{":shipped": {"S": "SHIPPED"}, ":placed": {"S": "PLACED"}}'
# 8. One transaction: create the order and take one unit out of stock, or do neither.
cat > tx.json <<JSON
[
{"Put": {"TableName": "$TABLE", "Item": {"customerId": {"S": "c-200"}, "orderId": {"S": "o-0002"}, "status": {"S": "PLACED"}, "createdAt": {"S": "2026-11-02T09:45:00Z"}, "total": {"N": "999"}},
"ConditionExpression": "attribute_not_exists(orderId)"}},
{"Update": {"TableName": "Stock", "Key": {"sku": {"S": "sku-9"}}, "UpdateExpression": "SET onHand = onHand - :one",
"ConditionExpression": "onHand >= :one", "ExpressionAttributeValues": {":one": {"N": "1"}}}}
]
JSON
aws dynamodb transact-write-items --region $REGION --transact-items file://tx.json
# 9. A change stream for Lambda or EventBridge Pipes, and a named backup before a risky release.
aws dynamodb update-table --region $REGION --table-name $TABLE --stream-specification StreamEnabled=true,StreamViewType=NEW_AND_OLD_IMAGES
aws dynamodb create-backup --region $REGION --table-name $TABLE --backup-name $TABLE-before-release
# 10. Has anything been throttled in the last hour?
aws cloudwatch get-metric-statistics --region $REGION --namespace AWS/DynamoDB --metric-name ThrottledRequests \
--dimensions Name=TableName,Value=$TABLE Name=Operation,Value=PutItem --statistics Sum --period 300 \
--start-time $(date -u -d '-1 hour' +%FT%TZ) --end-time $(date -u +%FT%TZ)
# Placeholders: pass in your own names. The values below are examples.
variable "region" {
type = string
default = "ap-south-1"
}
variable "table_name" {
type = string
default = "Orders"
}
provider "aws" {
region = var.region
}
resource "aws_dynamodb_table" "orders" {
name = var.table_name
billing_mode = "PAY_PER_REQUEST"
hash_key = "customerId"
range_key = "orderId"
attribute {
name = "customerId"
type = "S"
}
attribute {
name = "orderId"
type = "S"
}
attribute {
name = "status"
type = "S"
}
attribute {
name = "createdAt"
type = "S"
}
# Open orders by status. Only the keys and the total are copied into the index.
global_secondary_index {
name = "by-status"
hash_key = "status"
range_key = "createdAt"
projection_type = "INCLUDE"
non_key_attributes = ["total"]
}
ttl {
attribute_name = "expiresAt"
enabled = true
}
point_in_time_recovery {
enabled = true
recovery_period_in_days = 35
}
server_side_encryption {
enabled = true # uses the AWS managed key; add kms_key_arn for a customer managed key
}
deletion_protection_enabled = true
stream_enabled = true
stream_view_type = "NEW_AND_OLD_IMAGES"
tags = {
team = "orders"
}
}
resource "aws_dynamodb_table" "stock" {
name = "Stock"
billing_mode = "PAY_PER_REQUEST"
hash_key = "sku"
attribute {
name = "sku"
type = "S"
}
}
# Tell somebody when requests start to be throttled.
resource "aws_cloudwatch_metric_alarm" "throttled" {
alarm_name = "${var.table_name}-throttled"
namespace = "AWS/DynamoDB"
metric_name = "ThrottledRequests"
dimensions = { TableName = aws_dynamodb_table.orders.name }
statistic = "Sum"
period = 300
evaluation_periods = 1
threshold = 1
comparison_operator = "GreaterThanOrEqualToThreshold"
treat_missing_data = "notBreaching"
}
output "table_arn" {
value = aws_dynamodb_table.orders.arn
}
# pip install boto3
# An insert that is safe to retry, a paged query by customer, and an order plus a stock reduction in one transaction.
import boto3
from boto3.dynamodb.conditions import Key
from botocore.exceptions import ClientError
dynamodb = boto3.resource("dynamodb", region_name="ap-south-1")
orders = dynamodb.Table("Orders")
def place_order(customer_id, order_id, total):
"""Returns True when the order was created and False when it already existed, so a retried request is harmless."""
try:
orders.put_item(
Item={"customerId": customer_id, "orderId": order_id, "status": "PLACED", "total": total},
ConditionExpression="attribute_not_exists(orderId)",
)
return True
except ClientError as err:
if err.response["Error"]["Code"] == "ConditionalCheckFailedException":
return False
raise
def orders_of(customer_id, page_size=25):
"""Yields every order of one customer. A Query returns at most 1 MB at a time, so follow LastEvaluatedKey."""
kwargs = {"KeyConditionExpression": Key("customerId").eq(customer_id), "Limit": page_size}
while True:
page = orders.query(**kwargs)
yield from page["Items"]
if "LastEvaluatedKey" not in page:
return
kwargs["ExclusiveStartKey"] = page["LastEvaluatedKey"]
def order_and_reserve(customer_id, order_id, sku, total):
"""Creates the order and takes one unit from stock in a single transaction. Returns False when the item is out of stock.
The resource's client converts plain Python values to DynamoDB types for you, so nothing is serialised by hand here."""
try:
dynamodb.meta.client.transact_write_items(TransactItems=[
{"Put": {"TableName": "Orders", "Item": {"customerId": customer_id, "orderId": order_id, "status": "PLACED", "total": total},
"ConditionExpression": "attribute_not_exists(orderId)"}},
{"Update": {"TableName": "Stock", "Key": {"sku": sku}, "UpdateExpression": "SET onHand = onHand - :one",
"ConditionExpression": "onHand >= :one", "ExpressionAttributeValues": {":one": 1}}},
])
return True
except ClientError as err:
if err.response["Error"]["Code"] == "TransactionCanceledException":
print("cancelled:", [reason.get("Code") for reason in err.response.get("CancellationReasons", [])])
return False
raise
if __name__ == "__main__":
print("created:", place_order("c-300", "o-1001", 1200))
print("created again:", place_order("c-300", "o-1001", 1200))
for n in range(2, 6):
place_order("c-300", "o-100%d" % n, 100 * n)
print("orders of c-300:", [order["orderId"] for order in orders_of("c-300", page_size=2)])
print("reserved:", order_and_reserve("c-300", "o-2001", "sku-9", 999))
// dotnet add package AWSSDK.DynamoDBv2
// Audits every table in the Region: point-in-time recovery off, deletion protection off, indexes that copy every attribute,
// and tables with a time to live attribute missing. Edit the rules to match your own standard.
using Amazon.DynamoDBv2;
using Amazon.DynamoDBv2.Model;
using var db = new AmazonDynamoDBClient();
int problems = 0;
string? start = null;
do
{
var list = await db.ListTablesAsync(new ListTablesRequest { ExclusiveStartTableName = start });
foreach (string name in list.TableNames)
{
TableDescription table = (await db.DescribeTableAsync(name)).Table;
var backups = (await db.DescribeContinuousBackupsAsync(new DescribeContinuousBackupsRequest { TableName = name })).ContinuousBackupsDescription;
if (backups.PointInTimeRecoveryDescription?.PointInTimeRecoveryStatus != PointInTimeRecoveryStatus.ENABLED)
{
Console.WriteLine($"{name}: point-in-time recovery is off");
problems++;
}
if (table.DeletionProtectionEnabled != true)
{
Console.WriteLine($"{name}: deletion protection is off");
problems++;
}
foreach (GlobalSecondaryIndexDescription index in table.GlobalSecondaryIndexes ?? new List<GlobalSecondaryIndexDescription>())
{
if (index.Projection.ProjectionType == ProjectionType.ALL)
{
Console.WriteLine($"{name}/{index.IndexName}: the index copies every attribute, which you pay for on each write");
problems++;
}
}
var ttl = (await db.DescribeTimeToLiveAsync(name)).TimeToLiveDescription;
if (ttl.TimeToLiveStatus != TimeToLiveStatus.ENABLED)
Console.WriteLine($"{name}: no time to live attribute (fine if nothing in this table expires)");
}
start = list.LastEvaluatedTableName;
} while (start != null);
Console.WriteLine(problems == 0 ? "No problems found." : $"{problems} problem(s) found.");
return problems == 0 ? 0 : 1;
Best videos to explore
Videos picked for this service. Each one is labelled with its source, opens on YouTube if you prefer, and loads only when you press play.
Interview questions
BasicWhat is Amazon DynamoDB?
It’s AWS’s fully managed NoSQL database. You create tables of items, find them by a primary key, and DynamoDB handles servers, replication across Availability Zones and scaling. It’s built for fast key-based reads and writes at any size, not for joins or ad hoc SQL.
BasicWhat are a partition key and a sort key?
Together they form the primary key. The partition key is hashed to decide where an item is stored, and a query must name one value of it. The optional sort key orders the items that share a partition key, so you can ask for a range, such as the latest ten orders of a customer.
BasicWhat is the difference between on-demand and provisioned capacity?
On-demand bills each read and write request, so there is nothing to plan and it suits new or spiky workloads. Provisioned bills the read and write capacity you set per hour, with optional auto scaling, and usually costs less when traffic is steady and well understood. You can switch a table between modes.
IntermediateWhat is the difference between Query and Scan, and why does it matter?
A Query reads the items of one partition key value, using the keys of a table or index, so its cost depends on what it returns. A Scan reads every item and then filters, so you pay for the whole table however few items match. Filters don’t reduce the capacity a scan uses, so a scan on a growing table gets slower and dearer over time.
IntermediateHow do global and local secondary indexes differ?
A global secondary index has its own partition and sort key, can be added at any time, has its own capacity and is eventually consistent. A local secondary index keeps the table’s partition key with a different sort key, must be created with the table, can be read with strong consistency and limits each partition key value to 10 GB. Most designs need global indexes only.
IntermediateWhen would you use a strongly consistent read?
When the code needs its own write back at once, for example reading a balance right after updating it. A strongly consistent read returns the latest committed data from the table and costs twice the capacity of an eventually consistent one. Indexes and global table replicas in other Regions can’t serve strongly consistent reads, except for multi-Region strong consistency tables.
AdvancedHow do you design a table for several access patterns without a hot partition?
List the queries first, then pick a partition key with many values and even traffic and a sort key that supports the range queries. Put items that are read together under one key, and use a global secondary index for the other patterns. For a key that is inherently hot, split it with a suffix and read all the suffixes in parallel. Check the result with Contributor Insights and the throttling metrics under realistic load.
AdvancedHow do conditional writes and transactions help you build reliable workflows?
A conditional write turns an insert into an idempotent one and stops two workers updating the same state, because only one satisfies the condition. A transaction groups up to 100 actions across tables so they all succeed or none do, with a client token for safe retries. They cost double the capacity and are subject to conflicts, so keep them for places where partial success would corrupt data.
AdvancedHow would you choose between multi-Region eventual consistency and multi-Region strong consistency in global tables?
The default global table accepts writes in every Region and reconciles them afterwards with last-writer-wins, which gives low write latency and a small chance of losing a concurrent update. Multi-Region strong consistency makes reads consistent across Regions and gives a recovery point of zero, at the price of higher write latency and some limits, for example on transactions. Choose it for data like balances or inventory where a lost write is unacceptable, and the default for profiles and carts.
AdvancedRequests are throttled although consumed capacity is far below the limit. What is happening and how do you fix it?
Capacity is enforced per partition, so one hot key value can throttle while the table total looks low. Find the key with Contributor Insights, then spread it with a better key or a suffix, cache hot reads with DAX, and for provisioned tables check that auto scaling responds fast enough. A new on-demand table, or a sudden jump well above its earlier peak, can also throttle briefly while it adapts.
Similar or alternative services on other clouds
| Capability | AWS | Azure | Google Cloud |
|---|---|---|---|
| Service | Amazon DynamoDB | Azure Cosmos DB (API for NoSQL) | Firestore |
| Data model | Tables of items, partition key and sort key | Containers of JSON items, partition key | Collections of documents, with subcollections |
| Capacity | On-demand, or provisioned with auto scaling | Request units: provisioned, autoscale or serverless | No capacity to set; billed per operation |
| Secondary indexes | Global and local indexes that you design | Every property indexed by default, with a policy to tune | Single-field indexes automatic, composite ones declared |
| Consistency | Eventual by default, strong per read | Five levels, session by default | Strongly consistent reads and queries |
| Multi-Region | Global tables | Multi-region replication and writes | Multi-region locations |
| Change feed | DynamoDB Streams, 24 hours | Change feed | Realtime listeners and event triggers |
| Recovery | Point-in-time recovery, 1 to 35 days | Continuous backup, 7 or 30 days | Point-in-time recovery, 7 days, and scheduled backups |
| How you are billed | Request units or capacity units, plus storage | Request units or throughput per hour, plus storage | Reads, writes and deletes, plus storage |
Typical partners are AWS Lambda and Amazon API Gateway for a serverless back end, and Amazon EventBridge Pipes for reading a stream. Customer managed keys come from AWS KMS, and table metrics and alarms live in Amazon CloudWatch.
Did you find this article helpful?
Your answer helps us improve this page for the next reader.
Sources and further reading
CloudBrum wrote this page in its own words, using the provider’s public documentation listed below as the reference. Features, limits, names and prices change, so confirm anything that matters on the provider’s own pages before you decide.
- What is Amazon DynamoDB?Amazon Web Services
- Core components of Amazon DynamoDBAmazon Web Services
- Best practices for designing and using partition keysAmazon Web Services
- Using global secondary indexes in DynamoDBAmazon Web Services
- Amazon DynamoDB transactionsAmazon Web Services
- Point-in-time backups for DynamoDBAmazon Web Services
- Expiring items by using time to live (TTL)Amazon Web Services
- Service, account and table quotas in Amazon DynamoDBAmazon Web Services
- Amazon DynamoDB pricingAmazon Web Services
- Terraform AWS provider: aws_dynamodb_tableHashiCorp
