dynobase-icon
Dynobase

DynamoDB indexes: global and local secondary indexes

Rafal Wilinski

Written by Rafal Wilinski

Last updated: October 23rd, 2026

Managing indexes or replicas? Dynobase creates and removes global secondary indexes, follows their backfill progress, and manages replicas, tags and resource policies. Table settings in Dynobase

DynamoDB secondary indexes let you query a table through alternate keys. A global secondary index (GSI) can use a different partition key and supports eventually consistent reads; a local secondary index (LSI) retains the table's partition key and can support strongly consistent reads. Both store copies of selected attributes, add write and storage costs, and allow duplicate index key values.

GSI vs LSI at a glance

PropertyGlobal secondary index (GSI)Local secondary index (LSI)
Partition keyCan differ from the table; up to 4 attributesSame single partition-key attribute as the table
Sort keyOptional; up to 4 attributesRequired alternate sort-key attribute
Base-table schemaSimple or composite primary keyComposite primary key required
When createdWith the table or laterOnly with the table
Independent deletionYesNo
Read consistencyEventual onlyEventual or strong
Provisioned throughputSeparate read/write capacityShares the table's capacity
Capacity modeInherits the table's on-demand or provisioned modeUses the table's mode
Item-collection sizeNo LSI-style 10 GB limit10 GB per partition-key value, table plus LSI entries
Attributes not projectedFetch separately from the base tableCan fetch from the table, with extra read cost and latency
Number per table20 by default; quota increase can be requestedUp to 5

Use a GSI when you need another partitioning dimension or need to add an access pattern to an existing table. Consider an LSI when you need another sort order within the same collection and strongly consistent index reads. The LSI size constraint and creation-time decision are part of that choice, not reasons to rule LSIs out universally.

The AWS quotas page lists the current index limits. The base table's primary key remains its unique item identifier regardless of how many indexes you add.

DynamoDB local secondary index (LSI)

Suppose Orders has partition key customerId and sort key orderId. An LSI with customerId and createdAt returns one customer's orders by date instead of by order ID. Each index entry also includes the base-table primary key, so you can identify the original order.

Declare the LSI in CreateTable. You cannot add it later, remove it independently or change its key schema in place. If you discover that requirement after creating the table, use a GSI where eventual consistency is acceptable, or migrate to a new table.

The 10 GB limit applies to an item collection: all base-table items with the same partition-key value, plus their entries in all LSIs. It is not a limit on the whole table or on each individual item. A large customer with an unbounded order history can reach the limit even when other customers have tiny collections. Use ReturnItemCollectionMetrics: "SIZE" on supported writes to observe estimated collection size.

LSI reads and maintenance use the table's capacity. If you request an attribute that was not projected, DynamoDB can fetch it from the table, but that adds work and latency. Project frequently returned fields when that tradeoff is worthwhile. AWS documents these behaviors in its LSI guide.

DynamoDB global secondary index (GSI)

On the same Orders table, a GSI keyed by sellerId and createdAt answers “orders for this seller.” The base-table query still answers “orders for this customer.” That is a new access path, not a new source of truth: applications write the table and DynamoDB maintains the index.

GSI keys do not have to be unique. Two orders can share a seller and creation timestamp and both appear in the index. If their relative ordering matters, include a deterministic tie-breaker in the sort-key design. An index on email likewise does not enforce a unique-email constraint.

GSIs are eventually consistent. Setting ConsistentRead: true on a GSI query fails; it does not make the index fresher. For a read immediately after a write, use the known base-table primary key with a strongly consistent table read. Querying a GSI and then strongly reading its results cannot recover an item that has not appeared in the index yet.

GSIs have their own provisioned capacity, but write throttling is not isolated from the base table. If an affected index cannot keep up with propagated writes, the original table writes can be throttled. A low-cardinality status index can create this back-pressure even when table capacity looks healthy.

Multi-attribute GSI keys

GSIs support up to four attributes in the partition key and four in the sort key. You can use native attributes such as sellerId and marketplace together rather than maintaining a concatenated sellerMarketplace string.

A query must specify equality for every partition-key attribute. Sort-key conditions follow the declared attributes from left to right without gaps; an inequality or prefix condition must be last. This does not turn the index into arbitrary filtering across every column. Base-table and LSI key schemas retain their existing single-attribute components. See the GSI implementation guide for creation, multi-attribute examples and deployment checks.

Projections: which attributes an index stores

ProjectionContentsUseful when
KEYS_ONLYIndex keys and base-table primary keyYou need identifiers or will read the original item separately
INCLUDEKeys plus named non-key attributesThe query returns a small, stable subset of fields
ALLAll attributes from the indexed itemThe query needs the complete item and duplication is acceptable

With INCLUDE, each index can list up to 20 non-key attributes, and the sum of NonKeyAttributes across all secondary indexes cannot exceed 100. Projecting the same attribute into two indexes counts twice. That quota does not apply to ALL or KEYS_ONLY.

A GSI query can only return attributes stored in that GSI. It cannot automatically fetch missing fields from the table. An LSI can do that fetch, with additional cost. Also distinguish an index's stored projection from a request's ProjectionExpression: returning fewer attributes from a read does not by itself reduce the capacity charged for the data read.

Sparse index

An index is sparse when only some table items contain all of its required index key attributes. For a GSI keyed by sellerId and openOrderAt, write openOrderAt only on open orders. Remove it when an order closes, and the entry disappears from the index after propagation.

Sparse DynamoDB index containing only items that have its required key attributes

A partition-key-only GSI can also be sparse: omit its partition-key attribute from excluded items. The attribute must be absent, not an empty String or null. If you use a Boolean flag such as isOpen, it cannot itself be a key; use a supported scalar attribute representing the indexed collection.

Sparse indexes can replace repeated queries followed by filters when the subset has a useful query key. They do not make contains, arbitrary substring matching or an “attribute exists” condition valid partition-key queries. You still supply partition-key equality to Query.

Inverted index

An inverted index swaps the roles of a table's partition and sort keys. If a table stores edges as pk = USER#42 and sk = GROUP#7, querying the table lists a user's groups. A GSI keyed by sk and then pk lists the group's users.

Inverted DynamoDB index swapping the table partition and sort keys to query a relationship in reverse

This pattern fits memberships, friendships and other many-to-many relationships. It is not a full-text search engine's inverted index. Both directions still use DynamoDB key queries, and the reverse direction is eventually consistent because it is a GSI.

Creating a GSI on an existing table

This AWS CLI v2 example assumes an existing on-demand Orders table containing String attributes sellerId and createdAt. It adds a narrowly projected seller index:

For a provisioned table, also provide the index's ProvisionedThroughput. DynamoDB allocates resources, backfills qualifying existing items, and incorporates concurrent changes. The table stays available, but a skewed new index can affect table writes. Test the data distribution and schema before starting a production build.

Use OnlineIndexPercentageProgress and table write-throttling metrics to monitor progress and impact. Check that the specific index becomes ACTIVE before deploying queries against it. A table existing or being active is not sufficient proof that its new index is ready. The online index operations guide documents the phases and restrictions.

Querying the index with SDK v3 and boto3

After BySeller is active, query the same access pattern in JavaScript:

The boto3 resource interface supports this ordinary key query:

These examples return a page, not necessarily every seller order. Pass LastEvaluatedKey back as ExclusiveStartKey to continue. Neither GetItem nor BatchGetItem accepts IndexName; use the returned table keys for subsequent item reads.

What DynamoDB indexes cost

An index stores key attributes, projected values and per-entry storage overhead. Every affected GSI adds its own write work. A new base-table item that produces one entry in each of four GSIs requires a base-table write plus four index writes, not four writes total. Actual capacity depends on the separate item and index-entry sizes.

Updating only an unprojected non-key attribute does not change a GSI entry and consumes no write capacity for that index. Changing an indexed key value generally removes the old entry and inserts the new one. Narrow projections and sparse membership can therefore reduce ongoing costs.

In provisioned mode, you pay for configured index capacity. In on-demand mode, you pay for index requests. In both modes, storage is additional. Use the DynamoDB pricing calculator with the projected entry sizes and access rates, rather than assuming a flat percentage for indexes.

Choosing and operating indexes

Document a real query for every index, including the values callers know, required sort order, consistency and returned fields. Then check distribution, projection size and expected writes. A status-only GSI with heavy traffic may need a tenant dimension or sharding; adding read capacity will not repair concentrated writes.

Monitor index and table metrics together. Index reads use index capacity, but propagated writes connect their availability. If using a GUI, Dynobase table management can create or remove GSIs and show backfill progress. Keep the intended schema in infrastructure code so deployments and application queries agree.

Frequently Asked Questions

What is the difference between GSI and LSI?

A GSI can use different partition keys and supports only eventual consistency. An LSI shares the table partition key, supports strong reads, must be created with the table, and imposes a 10 GB item-collection limit.

How many secondary indexes can a DynamoDB table have?

The default quota is 20 GSIs per table, with increases available by request. A table can have up to 5 LSIs, declared when the table is created.

Are DynamoDB secondary index keys unique?

No. Multiple table items can have the same index key values. Only the complete base-table primary key uniquely identifies a table item.

Can a GSI throttle writes to the table?

Yes. If an affected GSI cannot keep up with index updates, DynamoDB can throttle writes to the base table. Separate GSI capacity does not provide write-failure isolation.

Can I add an index to an existing DynamoDB table?

You can add a GSI with UpdateTable and wait for its backfill to finish. You cannot add an LSI to an existing table.

Can I use GetItem on a DynamoDB index?

No. Read an index with Query or Scan and IndexName. To fetch a table item afterward, use its full base-table primary key in GetItem.

Dynobase is a Professional GUI Client for DynamoDB

Start your 7-day free trial today

Product Features

Download
/
Pricing
/
Member Portal
/
Privacy
/
EULA
/
Twitter
© 2026 Dynobase