DynamoDB GSI: creating and operating global secondary indexes

Written by Chameera Dulanga
Last updated: October 23rd, 2026
A DynamoDB global secondary index (GSI) is an alternate queryable view of a table, with its own partition key and optional sort key. DynamoDB copies qualifying items into it and propagates changes asynchronously, so GSI reads are always eventually consistent. You can create a GSI with the table or add one later without changing the table's primary key.
How a GSI works
Consider an Articles table with a String primary key, articleId. GetItem can retrieve article ARTICLE#100, but it cannot find articles by name. A GSI named name-index with partition key name provides that lookup. Query it with IndexName: "name-index" and name = "DynamoDB" to return matching articles.
“Global” means the index can collect items from across the base table's partitions. It does not mean multi-Region replication. A GSI has its own partitioning, storage and, in provisioned mode, capacity settings. It inherits the table's capacity mode, so an on-demand table cannot have a provisioned GSI.
Index keys need not be unique. Several articles can have the same name, and a GSI with a sort key can also contain duplicate full index-key combinations. Every index entry includes the base-table primary key so you can identify the original item. Writes go to the table, never directly to the GSI.
The default quota is 20 GSIs per table, and you can request an increase. That is a quota, not an absolute maximum. Build indexes for identified access patterns rather than treating the quota as a target.
GSI vs LSI
| Decision | GSI | LSI |
|---|---|---|
| Different partition key | Supported | Must use the table's partition key |
| Add to an existing table | Yes | No, creation time only |
| Strong reads | Not supported | Supported |
| Capacity in provisioned mode | Separate index settings | Shares table capacity |
| Item collection | No LSI-style 10 GB limit | 10 GB including base items and all LSI entries for that partition key |
| Count per table | 20 by default | Up to 5 |
An LSI requires a composite-key base table and cannot be deleted independently. A GSI is usually the practical option for adding a new query after launch, while an LSI can suit a bounded collection needing another strongly consistent sort order. The full index comparison covers the tradeoffs.
Decide what to project
An index stores its keys and the base-table primary key automatically. Choose what else it stores:
KEYS_ONLY: no extra attributes. Good for finding identifiers.INCLUDE: named non-key attributes, such as a title and publication state.ALL: every attribute on each qualifying item.
For INCLUDE, NonKeyAttributes accepts up to 20 names per index, with a total allowance of 100 across all GSIs and LSIs on the table. The same name projected into multiple indexes counts multiple times. ALL and KEYS_ONLY do not consume this allowance. These are the current Projection API rules.
A GSI query cannot fetch unprojected attributes automatically. Either project the fields the access pattern needs or use returned primary keys to fetch the original items separately. A request-level ProjectionExpression reduces returned data, but does not retroactively shrink the stored index or the capacity already used to read its entries.
Create a GSI with a new table
This SDK v3 example creates an on-demand Articles table and name-index. It uses INCLUDE so article bodies are not duplicated in the index.
The waiter's timeout is an application choice, not a creation-time guarantee. Do not declare title or publishedAt in AttributeDefinitions unless they are key attributes for another index. Non-key projections need no schema type declaration.
In the AWS console, configure secondary indexes while creating the table, or use the existing table's index management controls. Specify the same key schema and projection deliberately. A default projection of every attribute may duplicate large data that the query never needs.
Add and backfill a GSI on an existing table
If Articles already exists without name-index, use this alternative AWS CLI v2 command. It assumes on-demand capacity; do not run it after creating the same index above.
For a provisioned table, include ProvisionedThroughput in Create with the read and write capacity the index needs. Only one GSI can be created or deleted per UpdateTable call.
DynamoDB first allocates resources and then backfills existing qualifying items, incorporating concurrent table writes as it builds. This is an index backfill, not an application job that rewrites every base item. If a synthetic key attribute is missing from your old data, however, your application must populate it before those records qualify.
Monitor the build before using the index
CREATING with Backfilling: false indicates resource allocation; CREATING with Backfilling: true indicates the backfill phase. Wait until the specific index reports ACTIVE before querying it. A table waiter alone is not enough for an index added to an existing table.
Watch OnlineIndexPercentageProgress, the table's WriteThrottleEvents and ThrottledRequests, and the new index's distribution. Current AWS documentation says increasing provisioned index write capacity does not shorten the build, and OnlineIndexConsumedWriteCapacity and OnlineIndexThrottleEvents show zero during backfill. Size ongoing capacity for application traffic rather than treating it as a build-speed control.
The table remains available during creation, but skewed index keys and concurrent writes can cause operational impact. Schedule sensitive builds appropriately and be prepared to cancel during the backfill phase if table writes suffer. Base-table reads used for the build use internal capacity and are not charged as table reads. See online GSI operations for current phase restrictions.
Check existing data for index-key violations
An existing attribute may have inconsistent types across items because it was previously a non-key field. A new String index key does not accept Number values, nulls, oversized values or empty Strings. Violating existing items can be omitted during backfill while index creation still completes; after backfill, writes to items that violate the index schema are rejected.
Distinguish this from deliberately missing attributes in a sparse index. Audit types and sizes before creation, then verify representative records afterward. AWS provides a key-violation detection procedure; its documented detector does not catch empty String or Binary key values, so check those separately.
For visual management, Dynobase table management supports creating and removing GSIs and following backfill progress.
Query a GSI with SDK v3, boto3 or the CLI
First write a sample item to the base table, using the document client. This can run after the table exists:
The newly written article may not appear immediately because index propagation is asynchronous. This pagination loop reads all available pages; it is not a wait for propagation. body is not in the projection, so retrieve it from Articles by articleId if needed.
A boto3 client paginator handles the same paginated GSI query using typed values:
AWS CLI v2 automatically paginates unless you disable or limit its pagination:
The console also lets you select a table index when querying items. Supply the selected index's partition-key value, not necessarily the table's primary key. GetItem and BatchGetItem do not accept an index name.
Multi-attribute GSI keys
A GSI can have up to four native partition-key attributes and four native sort-key attributes. This can remove the need to create concatenated values solely for an index. It is particularly useful when existing items already contain all the natural fields needed for a new access pattern.
For example, articles could have tenantId, category, publishedAt and articleId. The following SDK v3 request adds an index to the existing on-demand table after previous index operations finish:
Use a current SDK or CLI with multi-attribute key support. The earlier sample item lacks tenantId and category, so it will not appear until you add valid values for both on the base item.
After the index becomes active and qualifying items exist, query all partition-key components by equality:
Sort-key conditions proceed left to right in the declared schema. You can constrain publishedAt alone, or constrain it by equality and then constrain articleId. You cannot skip publishedAt and query by articleId alone. An inequality, BETWEEN or begins_with condition must be the final sort-key condition, so the >= example cannot then narrow articleId.
Each component retains its own String, Number or Binary type. Native numeric components sort numerically without String padding. The feature applies only to GSIs; see the AWS multi-attribute pattern for schema and query rules, and the composite-key guide for base-table hierarchies.
Sparse indexes and missing results
DynamoDB only creates an index entry when an item has all required index key attributes. To index only published articles, give those items a publishedCategory key attribute and omit it from drafts. Removing the attribute removes index membership after propagation.
A sparse index is not an index with a configurable WHERE clause. Its membership follows attribute presence. An empty String or null is not a substitute for omission, because it is an invalid key value.
When a result is missing, check the table item, all index key values and their types, the query's case and aliases, the index status, and eventual consistency. ItemCount in index metadata is also not live: AWS updates it approximately every six hours. Do not use it as a propagation check or an exact business counter. See GSI metadata.
Write costs and throttling back-pressure
| Base-table change | GSI work, when applicable |
|---|---|
| New qualifying item | Insert an index entry |
| Change an index key value | Delete old entry and insert new entry |
| Remove a required index key | Delete the old entry |
| Change only a projected non-key value | Update the index entry |
| Change only unprojected non-key data | No index write |
| Item absent from index before and after | No index write |
Capacity is calculated from the index-entry size, independently of the base item. An ordinary index write rounds up in 1 KB units. Storage includes the table key, index key, projected data and 100 bytes of overhead per index entry. A narrow projection can therefore save both storage and write capacity.
For example, a new 1 KB table item that creates a 1 KB entry in each of two GSIs uses one base-table write unit and one for each GSI: three ordinary write units in total. Changing an indexed key can cost more because the index has to remove and insert entries. Use the pricing calculator with your actual item sizes, projections and update mix.
A GSI read does not consume base-table read capacity. Writes are more coupled: if a GSI cannot absorb changes, DynamoDB can throttle the base-table writes that generate them. This includes insufficient provisioned capacity, hot index partitions and on-demand constraints. A single PUBLISHED partition key can be a bottleneck even if the table uses well-distributed article IDs.
Inspect the exception's ThrottlingReasons and resource ARN, along with index CloudWatch metrics. IndexWriteKeyRangeThroughputExceeded calls for examining distribution; simply increasing total capacity may not help. The partition-key guide covers sharding and key selection.
Updating or replacing a GSI
You can change supported throughput settings, but cannot edit a GSI's key schema or projection in place. For either change, create a replacement index, wait for ACTIVE, verify representative queries, move application reads and only then remove the old index. Budget for both indexes during the migration.
To delete an unused index after callers have moved:
Deleting the index does not delete base-table items. Keep infrastructure definitions and application index names synchronized so a later deployment does not recreate an obsolete index or query a removed one.
Frequently Asked Questions
What is a GSI in DynamoDB?
Does a DynamoDB GSI have to be unique?
Can a table sort key be used as a GSI partition key?
Can I add a GSI to an existing table?
How long does a DynamoDB GSI take to create?
Can I change a GSI projection after creation?
Dynobase is a Professional GUI Client for DynamoDB
Start your 7-day free trial today