DynamoDB Query a GSI in Python (boto3)
Querying a global secondary index is a normal query plus one parameter: IndexName. The key condition then targets the index's keys, not the table's — here AlbumTitle-index lets us fetch songs by album, an access pattern the base table (Artist + SongTitle) can't serve without a scan.
Code
import boto3
client = boto3.client("dynamodb")
paginator = client.get_paginator("query")
items = []
for page in paginator.paginate(
TableName="Music",
IndexName="AlbumTitle-index",
KeyConditionExpression="#hashKey = :hashKeyValue",
ExpressionAttributeNames={"#hashKey": "AlbumTitle"},
ExpressionAttributeValues={":hashKeyValue": {"S": "Danzon"}},
):
items.extend(page["Items"])
print(f"Found {len(items)} songs on the album")Explanation
IndexName— names the GSI to query (TableNameis still required). TheKeyConditionExpressionuses the index's partition (and optional sort) key —AlbumTitlehere — with the same operators as a table query.- Eventual consistency only — GSIs replicate from the base table asynchronously. Passing
ConsistentRead=Trueon a GSI query doesn't upgrade it; it raises aValidationException. (Local secondary indexes do support strong consistency.) - You get projected attributes only — a GSI query returns what the index projects (
ALL,KEYS_ONLY, orINCLUDE-listed attributes) and cannot fetch the rest from the base table. Need an unprojected attribute? Follow up withget_itemon the table key, or widen the projection. - Keys aren't unique in a GSI — many items can share the same index key, and items missing the index key attribute simply don't appear (that's the sparse-index pattern).
- Pagination —
client.get_paginator("query")followsLastEvaluatedKeyacross pages exactly as on a table query; eachpagecarries anItemslist. - On the resource API, the same query is
table.query(IndexName="AlbumTitle-index", KeyConditionExpression=Key("AlbumTitle").eq("Danzon"))with native Python values.
Do it visually
The DynamoDB Expression Builder builds the key condition + name/value maps for index queries and copies runnable boto3 code.
To browse a table's indexes and run GSI queries from a form — paginated grid, copy-as-code — download DynoTable.
Related examples
- DynamoDB Query a GSI in Node.js — the same index query with AWS SDK v3.
- DynamoDB Query a GSI with the AWS CLI — the same index query from the shell.
- DynamoDB Query in Python — querying the base table.
- GSI vs. LSI — which index type fits the access pattern.
- Why GSIs are eventually consistent — the replication lag explained.
- "The table does not have the specified index" — the index name doesn't match (GSI names are case-sensitive).
- "Consistent reads are not supported on global secondary indexes" — why the consistent-read flag fails on a GSI.
References
- Query — Amazon DynamoDB API Reference
- DynamoDB.Paginator.Query — Boto3 documentation
- Using Global Secondary Indexes in DynamoDB — Amazon DynamoDB Developer Guide
Last verified 2026-07-13 against the official AWS documentation linked above.