Amazon DynamoDB via SDK: Your First Table
DynamoDB is a managed key-value and document database with single-digit-millisecond reads at any scale.
Busque em todas as páginas da documentação
DynamoDB is a managed key-value and document database with single-digit-millisecond reads at any scale.
This page creates a table, waits for it, then puts, gets, and queries items - all through the document interface, which lets you use plain objects instead of DynamoDB's typed attribute values.
Quick-reference recipe card - copy-paste ready.
# --- Python (boto3) ---
import boto3
table = boto3.resource("dynamodb", region_name="us-east-1").Table("Orders")
table.put_item(Item={"customerId": "c-1", "orderId": "o-100", "total": 42})
item = table.get_item(Key={"customerId": "c-1", "orderId": "o-100"})["Item"]
print(item)// --- TypeScript (AWS SDK v3) ---
import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
import { DynamoDBDocumentClient, PutCommand, GetCommand } from "@aws-sdk/lib-dynamodb";
const doc = DynamoDBDocumentClient.from(new DynamoDBClient({ region: "us-east-1" }));
await doc.send(new PutCommand({ TableName: "Orders", Item: { customerId: "c-1", orderId: "o-100", total: 42 } }));
const { Item } = await doc.send(new GetCommand({ TableName: "Orders", Key: { customerId: "c-1", orderId: "o-100" } }));
console.log(Item);When to reach for this:
Create a table with a partition and sort key, wait until it exists, write a few items, get one by key, query all items for one customer, then delete the table.
# --- Python (boto3) ---
import boto3
from boto3.dynamodb.conditions import Key
ddb = boto3.client("dynamodb", region_name="us-east-1")
res = boto3.resource("dynamodb", region_name="us-east-1")
# 1. Create the table: define ONLY the key attributes.
ddb.create_table(
TableName="Orders",
KeySchema=[
{"AttributeName": "customerId", "KeyType": "HASH"}, # partition key
{"AttributeName": "orderId", "KeyType": "RANGE"}, # sort key
],
AttributeDefinitions=[
{"AttributeName": "customerId", "AttributeType": "S"},
{"AttributeName": "orderId", "AttributeType": "S"},
],
BillingMode="PAY_PER_REQUEST",
)
ddb.get_waiter("table_exists").wait(TableName="Orders")
# 2. Write items with plain Python types (document interface).
table = res.Table("Orders")
table.put_item(Item={"customerId": "c-1", "orderId": "o-100", "total": 42})
table.put_item(Item={"customerId": "c-1", "orderId": "o-101", "total": 17})
# 3. Get one item by its full key.
print(table.get_item(Key={"customerId": "c-1", "orderId": "o-100"})["Item"])
# 4. Query every order for one customer.
resp = table.query(KeyConditionExpression=Key("customerId").eq("c-1"))
print([i["orderId"] for i in resp["Items"]])
# 5. Clean up.
ddb.delete_table(TableName="Orders")// --- TypeScript (AWS SDK v3) ---
import {
DynamoDBClient, CreateTableCommand, DeleteTableCommand, waitUntilTableExists,
} from "@aws-sdk/client-dynamodb";
import {
DynamoDBDocumentClient, PutCommand, GetCommand, QueryCommand,
} from "@aws-sdk/lib-dynamodb";
const base = new DynamoDBClient({ region: "us-east-1" });
const doc = DynamoDBDocumentClient.from(base);
// 1. Create the table: define ONLY the key attributes.
await base.send(new CreateTableCommand({
TableName: "Orders",
KeySchema: [
{ AttributeName: "customerId", KeyType: "HASH" }, // partition key
{ AttributeName: "orderId", KeyType: "RANGE" }, // sort key
],
AttributeDefinitions: [
{ AttributeName: "customerId", AttributeType: "S" },
{ AttributeName: "orderId", AttributeType: "S" },
],
BillingMode: "PAY_PER_REQUEST",
}));
await waitUntilTableExists({ client: base, maxWaitTime: 120 }, { TableName: "Orders" });
// 2. Write items with plain objects (document interface).
await doc.send(new PutCommand({ TableName: "Orders", Item: { customerId: "c-1", orderId: "o-100", total: 42 } }));
await doc.send(new PutCommand({ TableName: "Orders", Item: { customerId: "c-1", orderId: "o-101", total: 17 } }));
// 3. Get one item by its full key.
const { Item } = await doc.send(new GetCommand({ TableName: "Orders", Key: { customerId: "c-1", orderId: "o-100" } }));
console.log(Item);
// 4. Query every order for one customer.
const q = await doc.send(new QueryCommand({
TableName: "Orders",
KeyConditionExpression: "customerId = :c",
ExpressionAttributeValues: { ":c": "c-1" },
}));
console.log((q.Items ?? []).map((i) => i.orderId));
// 5. Clean up.
await base.send(new DeleteTableCommand({ TableName: "Orders" }));What this demonstrates:
GetItem needs the full primary key; Query targets one partition key and returns its items.PAY_PER_REQUEST billing means no capacity planning for a first table.boto3.resource(...).Table and lib-dynamodb) marshals plain values to and from the wire format {"S": ...}, {"N": ...} so you rarely see it.Query reads a single partition efficiently; Scan reads the entire table and costs far more.Query is efficient because it targets one partition key. Scan reads everything and filters after the fact, so it grows more expensive as the table grows.
# --- Python (boto3) ---
from boto3.dynamodb.conditions import Key
# Efficient: query one partition, optionally narrowing the sort key.
table.query(
KeyConditionExpression=Key("customerId").eq("c-1") & Key("orderId").begins_with("o-1")
)// --- TypeScript (AWS SDK v3) ---
// Efficient: query one partition, optionally narrowing the sort key.
await doc.send(new QueryCommand({
TableName: "Orders",
KeyConditionExpression: "customerId = :c AND begins_with(orderId, :p)",
ExpressionAttributeValues: { ":c": "c-1", ":p": "o-1" },
}));Reach for Scan only for small tables or one-off maintenance, never for a hot request path.
Pass a ConditionExpression to make writes safe under concurrency - for example, only insert if the item does not already exist with attribute_not_exists(customerId).
AttributeDefinitions should list only key (and index) attributes. Fix: declare just the keys; everything else is added per item.CREATING and rejects writes. Fix: wait on table_exists after CreateTable.GetItem needs the complete primary key. Fix: provide both partition and sort key, or use Query when you only have the partition key.Scan reads everything and gets slow and costly at scale. Fix: design a key or index so you can Query instead.{"S": ...} typed values everywhere. Fix: use the document interface (resource/lib-dynamodb) for plain objects.ConsistentRead=True when you need the latest write.| Alternative | Use When | Don't Use When |
|---|---|---|
| DynamoDB (this page) | Known access patterns, key lookups at scale | You need SQL joins or ad-hoc queries |
| RDS / Aurora | Relational data, transactions, flexible queries | You want a connectionless, auto-scaling store |
| ElastiCache | Ultra-low-latency ephemeral cache | You need durable primary storage |
| S3 | Large blobs and files | Small structured records queried by key |
| DynamoDB + Global Secondary Index | A second access pattern on the same data | The base table's key already serves the query |
Only the primary key: a partition key, optionally plus a sort key, listed in KeySchema and AttributeDefinitions. Every other attribute is added freely per item.
A convenience layer (boto3.resource(...).Table and @aws-sdk/lib-dynamodb) that converts plain numbers, strings, and objects to and from DynamoDB's typed wire format automatically.
Use Query to read items for a single partition key efficiently. Use Scan only when you truly need to read the whole table, since it costs and slows down with size.
GetItem fetches exactly one item, so it requires the complete primary key. If you only have the partition key, use Query to get all matching items instead.
On-demand capacity: you pay per read and write with no capacity to provision. It is the simplest choice for a first table or spiky traffic.
By default reads are eventually consistent, so a just-written value may not appear immediately. Set ConsistentRead=True on GetItem or Query when you need the latest data.
Create a Global Secondary Index (GSI) with a different key, either at table creation or via UpdateTable. Then Query the index the same way you query the base table.
Yes. Use UpdateItem with an UpdateExpression to modify specific attributes without rewriting the whole item, and add a ConditionExpression for safe concurrent updates.
Add a ConditionExpression such as attribute_not_exists(customerId) to a PutItem. The write fails if the item already exists, which is how you do a safe insert.
Start from your access patterns, not your entities. Choose keys so your most common reads become Query calls on a single partition, and add indexes for secondary patterns.
Stack versions: This page was written for boto3 1.43.x (Python 3.10+) and the AWS SDK for JavaScript v3 (Node.js 18+).
Revisado por Chris St. John·Última atualização: 24 de jul. de 2026