DynamoDB BatchGetItem in Python (boto3)

batch_get_item fetches up to 100 items by primary key in a single request (16 MB max). With the boto3 low-level client you pass a RequestItems map of table → keys — and you must loop on UnprocessedKeys, because a batch can legally return only part of what you asked for.

Code

import time

import boto3

client = boto3.client("dynamodb")

request_items = {
    "Music": {
        "Keys": [
            {"Artist": {"S": "Arturo Sandoval"}, "SongTitle": {"S": "Cubano Chant"}},
            {"Artist": {"S": "Arturo Sandoval"}, "SongTitle": {"S": "A Mis Abuelos"}},
            {"Artist": {"S": "Ella Fitzgerald"}, "SongTitle": {"S": "Misty"}},
        ]
    }
}

items = []
attempt = 0

while request_items:
    response = client.batch_get_item(RequestItems=request_items)
    items.extend(response["Responses"].get("Music", []))

    # A partial result is NOT an error: throttling, a >16 MB response, or an
    # internal failure returns the leftovers in UnprocessedKeys. Retry them
    # with exponential backoff.
    request_items = response["UnprocessedKeys"]
    if request_items:
        attempt += 1
        time.sleep(min(0.1 * 2**attempt, 5))

print(f"Fetched {len(items)} items")

Explanation

  • RequestItems — a map of table name → {"Keys": [...]}; one request can span multiple tables. Every key must be the full primary key (partition + sort for a composite key), in DynamoDB JSON ({"S": ...}, {"N": ...}). More than 100 keys, or the same key twice, raises a ValidationException.
  • Responses — a map of table name → the items found. Items come back in no particular order, and keys that don't exist simply don't appear — match results to requests by their key attributes.
  • UnprocessedKeys — the retry loop above is not optional. If the response passes 16 MB, throughput runs out, or a partition read passes 1 MB, DynamoDB returns the remainder here in RequestItems form, ready to feed straight back in (an empty map means done — falsy in Python, which is what ends the while). AWS strongly recommends exponential backoff between retries.
  • Consistency — batch reads are eventually consistent by default; set "ConsistentRead": True per table for strongly consistent reads.
  • Per table you can also pass ProjectionExpression (with ExpressionAttributeNames) to fetch only some attributes.
  • Prefer native Python types instead of DynamoDB JSON? The resource API offers dynamodb.batch_get_item(...) with plain values, but the retry contract is the same — UnprocessedKeys is yours to drain either way.

Do it visually

Prefer not to hand-assemble DynamoDB-JSON key maps? The DynamoDB Expression Builder builds typed key/value maps and copies runnable code, and the item size calculator shows how close a batch gets to the 16 MB ceiling.

To fetch and inspect items across tables in a GUI — no retry loops to write — download DynoTable.

References

Last verified 2026-07-13 against the official AWS documentation linked above.

Work with DynamoDB without the Console

DynoTable is a fast desktop client for DynamoDB — browse tables, run SQL-style queries, and edit items locally.