DynamoDB Basics for Developers
Learn DynamoDB fundamentals — tables, primary keys, queries, scans, GSIs, single-table design, and using boto3 in Python.
What you'll learn
- ✓DynamoDB data model: tables, items, attributes, primary keys
- ✓Query vs Scan and when to use each
- ✓Global and Local Secondary Indexes
- ✓CRUD operations with boto3
Prerequisites
- •Basic understanding of databases
- •Python basics for the boto3 examples
DynamoDB is AWS’s fully managed NoSQL database. It handles scaling, replication, and backups automatically. You get single-digit millisecond latency at any scale — but you must design your access patterns upfront.
Core concepts
- Table: a collection of items (like a SQL table)
- Item: a single record (like a row), stored as JSON
- Attribute: a field on an item (like a column)
- Primary key: uniquely identifies each item
Primary key types
Partition key only: a single attribute that DynamoDB hashes to determine storage location.
Table: Users
PK: userId
Partition key + sort key (composite): combines two attributes. Items with the same partition key are stored together and sorted by the sort key.
Table: Orders
PK: customerId
SK: orderDate#orderId
Creating a table with boto3
import boto3
dynamodb = boto3.resource("dynamodb")
table = dynamodb.create_table(
TableName="Users",
KeySchema=[
{"AttributeName": "userId", "KeyType": "HASH"},
],
AttributeDefinitions=[
{"AttributeName": "userId", "AttributeType": "S"},
],
BillingMode="PAY_PER_REQUEST",
)
table.wait_until_exists()
CRUD operations
Put (create/replace)
table = dynamodb.Table("Users")
table.put_item(Item={
"userId": "user-001",
"name": "Alice",
"email": "alice@example.com",
"age": 30,
"tags": ["admin", "active"],
})
Get
response = table.get_item(Key={"userId": "user-001"})
item = response.get("Item")
Update
table.update_item(
Key={"userId": "user-001"},
UpdateExpression="SET age = :age, #n = :name",
ExpressionAttributeNames={"#n": "name"},
ExpressionAttributeValues={":age": 31, ":name": "Alice Smith"},
)
Delete
table.delete_item(Key={"userId": "user-001"})
Query vs Scan
Query fetches items by partition key (and optionally filters by sort key). It is fast and efficient.
from boto3.dynamodb.conditions import Key
response = table.query(
KeyConditionExpression=Key("customerId").eq("cust-001")
& Key("orderDate").begins_with("2026-06")
)
items = response["Items"]
Scan reads every item in the table. It is slow and expensive — avoid in production.
response = table.scan(
FilterExpression=Key("age").gt(25)
)
Global Secondary Indexes (GSI)
A GSI lets you query by a different attribute than the primary key.
table = dynamodb.create_table(
TableName="Orders",
KeySchema=[
{"AttributeName": "orderId", "KeyType": "HASH"},
],
AttributeDefinitions=[
{"AttributeName": "orderId", "AttributeType": "S"},
{"AttributeName": "customerId", "AttributeType": "S"},
],
GlobalSecondaryIndexes=[{
"IndexName": "CustomerIndex",
"KeySchema": [
{"AttributeName": "customerId", "KeyType": "HASH"},
],
"Projection": {"ProjectionType": "ALL"},
}],
BillingMode="PAY_PER_REQUEST",
)
Query the GSI:
response = table.query(
IndexName="CustomerIndex",
KeyConditionExpression=Key("customerId").eq("cust-001")
)
Batch operations
with table.batch_writer() as batch:
for i in range(100):
batch.put_item(Item={
"userId": f"user-{i:03d}",
"name": f"User {i}",
})
Conditional writes
table.put_item(
Item={"userId": "user-001", "name": "Alice", "version": 1},
ConditionExpression="attribute_not_exists(userId)",
)
This fails if the item already exists — useful for preventing overwrites.
Summary
DynamoDB gives you predictable performance at any scale, but demands that you design your keys and indexes around your access patterns. Use composite keys for one-to-many relationships, GSIs for alternate query patterns, and avoid scans in production. Start with PAY_PER_REQUEST billing and switch to provisioned capacity when your patterns stabilize.
Related articles
- AWS DynamoDB Data Modeling: Single-Table Design Patterns
Learn DynamoDB single-table design patterns, composite keys, GSIs, and data modeling strategies to build efficient NoSQL applications on AWS.
- AWS AWS DynamoDB Data Modeling Patterns
Practical DynamoDB modeling patterns including single-table design, composite keys, GSIs, and access-pattern-first thinking that keeps queries cheap at scale.
- AWS AWS RDS vs Aurora vs DynamoDB: Choosing Your Database
Trade-offs between RDS, Aurora, and DynamoDB across cost, scaling, latency, and operational overhead, with a concrete decision framework.
- AWS AWS EC2 Basics: Your First Virtual Server
A beginner-friendly tour of Amazon EC2 — instance types, AMIs, key pairs, security groups, launching via the console, SSH access, the free tier, and the difference between stopping and terminating an instance.