Get All Items from DynamoDB in Python (boto3)
Reading a whole table in boto3 means paginating a scan to the end. Each response caps at 1 MB, and the low-level client's built-in paginator follows LastEvaluatedKey across every page for you (how DynamoDB cursors work).
Which boto3 API you pick matters more here than the pagination does, and the paginator is only half the reason.
Code
import boto3
client = boto3.client("dynamodb")
paginator = client.get_paginator("scan")
items = []
for page in paginator.paginate(TableName="Music"):
items.extend(page["Items"])
print(f"Table holds {len(items)} items")Explanation
- Paginators belong to the client, not the resource —
boto3.resource("dynamodb").Table(…).scanhas no paginator at all, so there you write theLastEvaluatedKeyloop yourself. That alone is a good reason to use the low-level client for a full read. - The resource API converts numbers to
Decimal— a stored{"N": "1994"}comes back asDecimal('1994'), whichjson.dumpsrefuses to serialize without a custom encoder. The client above hands you the raw{"N": "1994"}and leaves the conversion to you (the encoding). - Tune the paginator instead of replacing it —
paginator.paginate(TableName="Music", PaginationConfig={"PageSize": 500, "MaxItems": 10000}). Boto3 definesPageSizeas "the number of items returned per page of each result" andMaxItemsas a cap on the total, which emits aNextTokenyou resume from withStartingToken. - Parallel scans need one client per thread, built carefully —
SegmentandTotalSegmentssplit the work, and boto3's own guidance is that clients are thread-safe while sessions and resources are not. It also warns that "Invokingboto3.client()inside of a concurrent context may result in response ordering issues". Build the client before you fan out, or give each worker its ownboto3.session.Session()(when parallel is worth it). itemsgrows to the size of the table — handle eachpageinside the loop rather than extending a list you keep, unless you already know the table is small.- A scan bills every byte it reads, on every run —
ProjectionExpressionshrinks the response and not the bill (why); aFilterExpressiondrops items after they are read and charged (Scan with a filter). On a hot path you want a query.
Do it visually
A full scan's bill is item size times item count, rounded up in 4 KB units. The item size calculator gives you the per-item half of that from a pasted item.
DynoTable pages through a live table in an infinite-scrolling grid instead, and its SQL editor names the operation your query compiles to before you run it. The RCU estimate appears only when table metadata supports it. Download DynoTable.
Related examples
- Get all items in Node.js — the same full read with an explicit loop.
- Get all items with the AWS CLI — the CLI pages for you.
- DynamoDB Scan in Python — scanning with a
FilterExpression. - Parallel scans — Segment/TotalSegments, worker counts, and when to bother.
- Why is my DynamoDB Scan slow and expensive? — the cost model and how to avoid it.
- DynamoDB ProvisionedThroughputExceededException — reading the whole table is the classic way to hit it.
- "The provided starting key is invalid" — a mangled resume key in the pagination loop.
References
- Scan — Amazon DynamoDB API Reference
- DynamoDB.Paginator.Scan — Boto3 documentation
- Scanning tables in DynamoDB — Amazon DynamoDB Developer Guide
- DynamoDB read and write operations (capacity unit consumption) — Amazon DynamoDB Developer Guide
- Paginators — Boto3 documentation
- Clients (thread safety) — Boto3 documentation
Last verified 2026-07-28 against the official AWS documentation linked above.