DynamoDB Global Secondary Index
A Global Secondary Index (GSI) lets you query a DynamoDB table using completely different attributes — not just the table's primary key. It creates an entirely separate index with its own partition key and optional sort key. GSIs are one of the most powerful and frequently used DynamoDB features.
Why GSIs Are Essential
A DynamoDB table is optimized for one primary access pattern — its primary key. Real applications need multiple access patterns. A user management table needs lookups by UserID, by email, by city, and by account status — often all four.
GSIs solve this without duplicating data into separate tables.
How a GSI Works
A GSI is like creating a separate copy of your table reorganized around a different key. DynamoDB automatically keeps the GSI synchronized with the base table as you write data.
Example Setup
Base Table: Users Partition Key: UserID Sort Key: (none) Data: ┌──────────┬──────────────────────┬─────────┬──────────────┐ │ UserID │ Email │ City │ Plan │ ├──────────┼──────────────────────┼─────────┼──────────────┤ │ U001 │ arjun@example.com │ Mumbai │ Premium │ │ U002 │ sara@example.com │ Delhi │ Free │ │ U003 │ kiran@example.com │ Mumbai │ Premium │ │ U004 │ nisha@example.com │ Chennai │ Free │ └──────────┴──────────────────────┴─────────┴──────────────┘
Problem
You cannot query by City or Plan using the base table because these are not key attributes.
Solution: Add a GSI
GSI Name: CityPlanIndex Partition Key: City Sort Key: Plan GSI View of the Same Data: ┌─────────┬──────────────┬──────────┬──────────────────────┐ │ City │ Plan │ UserID │ Email │ ├─────────┼──────────────┼──────────┼──────────────────────┤ │ Chennai │ Free │ U004 │ nisha@example.com │ │ Delhi │ Free │ U002 │ sara@example.com │ │ Mumbai │ Premium │ U001 │ arjun@example.com │ │ Mumbai │ Premium │ U003 │ kiran@example.com │ └─────────┴──────────────┴──────────┴──────────────────────┘ Query: City = "Mumbai" AND Plan = "Premium" Result: U001 (Arjun) and U003 (Kiran)
GSI Partition Key Does Not Need to Be Unique
Unlike the base table's partition key, a GSI partition key does not need to be unique. Multiple items can share the same GSI partition key value — this is normal and expected. City = "Mumbai" can apply to thousands of users.
GSI Capacity
Each GSI has its own separate read and write capacity settings (in provisioned mode) or scales independently (in on-demand mode). Write operations on the base table that affect GSI attributes consume capacity from both the base table and the GSI. Size your GSI capacity accordingly.
GSI Write Amplification
When you write a User item: Base Table write: consumes 1 WCU CityPlanIndex GSI: also consumes 1 WCU (because City and Plan are indexed) Total cost: 2 WCUs for 1 user record With 3 GSIs, a single write to the base table costs 4 WCUs total.
GSI Eventual Consistency
Reads on a GSI are always eventually consistent. When you write to the base table, the GSI updates asynchronously — usually within milliseconds, but not instantaneously. You cannot request strongly consistent reads on a GSI.
If you need the absolute latest value for an item you found through a GSI, fetch the item again from the base table using its primary key with ConsistentRead: true.
Sparse Indexes
A GSI only includes items that have the GSI's partition key attribute present. Items missing that attribute do not appear in the GSI. You can use this deliberately to create a sparse index.
Example: Index Only Overdue Orders
Base Table: Orders (thousands of items) Only overdue orders have the attribute "OverdueDate". Delivered orders do not have this attribute. GSI on "OverdueDate": → Includes only the overdue orders → A small index instead of a full copy of the table Query the GSI → instantly retrieves only overdue orders without scanning the full table
Sparse indexes are a powerful pattern for filtering large tables down to a small relevant subset.
Projected Attributes
Like LSIs, GSIs support three projection types:
- KEYS_ONLY — Index key attributes only; fetches non-key data from the base table when needed.
- INCLUDE — Key attributes plus specific named attributes.
- ALL — All base table attributes replicated into the index.
Use KEYS_ONLY or INCLUDE to reduce GSI storage costs. Use ALL when you need to avoid extra base table reads.
GSI Limits
| Limit | Value |
|---|---|
| Max GSIs per table | 20 |
| Can be added after table creation | Yes |
| Can be deleted | Yes |
| Read consistency | Eventually consistent only |
| Item collection size limit | None (unlike LSI) |
Adding a GSI to an Existing Table
You can add a GSI to a table that already has data. DynamoDB backfills the index by reading all existing items and populating the GSI. During backfill, the table remains fully operational — reads and writes continue without interruption. Backfill time depends on the table size and available capacity.
When to Use a GSI
- You need to query by an attribute that is not the primary key.
- You need a different partition key than the base table uses.
- You want a sparse index for a subset of items.
- You need to add a new access pattern to an existing table.
Summary
GSIs are a fundamental tool for supporting multiple query patterns on a single DynamoDB table. They use their own partition key (any attribute), scale independently, and can be added at any time. The trade-off is that they consume extra write capacity and only support eventual consistency. Use them strategically to cover all your application's query needs without resorting to expensive Scans.
