Python
Amazon DynamoDB
AWS
Database Access
Programming Tutorial

How can I access Amazon DynamoDB via Python?

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

Introduction

DynamoDB access from Python is typically done with boto3, which provides both high-level resource APIs and low-level client APIs. A reliable setup requires correct AWS credentials, region configuration, and table key design awareness. This guide covers practical CRUD, query patterns, and production safeguards.

Configure Python and AWS Credentials

Install boto3 and confirm credentials are available in your environment.

bash
python -m pip install boto3
aws configure

Minimal verification script:

python
1import boto3
2
3session = boto3.Session()
4print("Region:", session.region_name)

Credentials can come from environment variables, shared credentials file, IAM role, or container task role. Prefer role-based auth in cloud deployments.

Connect Using Resource API

The resource API is convenient for common table operations.

python
1import boto3
2
3region = "us-east-1"
4dynamodb = boto3.resource("dynamodb", region_name=region)
5table = dynamodb.Table("Users")
6
7print(table.table_status)

Use this for readable code when you work mainly with item-level operations.

Insert and Read Items

DynamoDB requires full primary key values for direct reads.

python
1from decimal import Decimal
2
3# put item
4table.put_item(
5    Item={
6        "user_id": "u-100",
7        "created_at": "2026-03-01T10:00:00Z",
8        "name": "Nina",
9        "score": Decimal("91.5")
10    }
11)
12
13# get item (must include full primary key)
14resp = table.get_item(
15    Key={
16        "user_id": "u-100",
17        "created_at": "2026-03-01T10:00:00Z"
18    }
19)
20
21print(resp.get("Item"))

Use Decimal for numeric values when precision matters.

Query by Partition Key

For efficient reads, use query rather than scan whenever possible.

python
1from boto3.dynamodb.conditions import Key
2
3resp = table.query(
4    KeyConditionExpression=Key("user_id").eq("u-100")
5)
6
7for item in resp["Items"]:
8    print(item["created_at"], item["score"])

query uses key access paths and scales much better than full-table scans.

Update and Delete Items

Use update expressions to modify selected attributes atomically.

python
1table.update_item(
2    Key={"user_id": "u-100", "created_at": "2026-03-01T10:00:00Z"},
3    UpdateExpression="SET #n = :new_name",
4    ExpressionAttributeNames={"#n": "name"},
5    ExpressionAttributeValues={":new_name": "Nina Patel"}
6)
7
8table.delete_item(
9    Key={"user_id": "u-100", "created_at": "2026-03-01T10:00:00Z"}
10)

Expressions help avoid racey read-modify-write flows.

Handle Pagination and Throughput

Large queries and scans return paginated results. Loop with LastEvaluatedKey.

python
1items = []
2last_key = None
3
4while True:
5    kwargs = {
6        "KeyConditionExpression": Key("user_id").eq("u-100")
7    }
8    if last_key:
9        kwargs["ExclusiveStartKey"] = last_key
10
11    resp = table.query(**kwargs)
12    items.extend(resp["Items"])
13
14    last_key = resp.get("LastEvaluatedKey")
15    if not last_key:
16        break
17
18print("Total items:", len(items))

Also monitor consumed capacity and add retry logic for throttling.

Local Development with DynamoDB Local

For offline tests, use DynamoDB Local endpoint.

python
1local = boto3.resource(
2    "dynamodb",
3    region_name="us-east-1",
4    endpoint_url="http://localhost:8000",
5    aws_access_key_id="dummy",
6    aws_secret_access_key="dummy"
7)

This enables repeatable integration tests without touching production resources.

Create Tables Programmatically

For integration tests or bootstrap scripts, create tables from Python.

python
1client = boto3.client("dynamodb", region_name="us-east-1")
2
3client.create_table(
4    TableName="Users",
5    KeySchema=[
6        {"AttributeName": "user_id", "KeyType": "HASH"},
7        {"AttributeName": "created_at", "KeyType": "RANGE"}
8    ],
9    AttributeDefinitions=[
10        {"AttributeName": "user_id", "AttributeType": "S"},
11        {"AttributeName": "created_at", "AttributeType": "S"}
12    ],
13    BillingMode="PAY_PER_REQUEST"
14)

After creation, wait for active status before writes to avoid transient errors.

Conditional Writes for Concurrency Safety

Use condition expressions to prevent accidental overwrite.

python
1table.put_item(
2    Item={"user_id": "u-200", "created_at": "2026-03-02T10:00:00Z", "name": "Kai"},
3    ConditionExpression="attribute_not_exists(user_id)"
4)

This protects data integrity when multiple workers write concurrently.

Use CloudWatch metrics and structured logging around latency, retries, and throttling counts so DynamoDB access issues can be diagnosed quickly in production services.

Common Pitfalls

  • Using scan for everything instead of designing key-based query access.
  • Forgetting full primary key values for get_item and delete_item.
  • Ignoring pagination and accidentally processing only first page of results.
  • Hardcoding long-term credentials instead of using IAM roles.
  • Storing floating-point numbers directly and getting precision surprises.

Summary

  • Access DynamoDB in Python with boto3 resource or client APIs.
  • Use query with key conditions for scalable reads.
  • Handle pagination, retries, and throughput limits explicitly.
  • Prefer IAM roles and environment-based credential resolution.
  • Use DynamoDB Local for safe, repeatable local testing.

Related reading
Course
Beginner
27 lessons
10 hours
System Design Fundamentals

Build a strong foundation in designing scalable, reliable distributed systems.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

All Rights Reserved.