DEV Community

Joud Awad
Joud Awad

Posted on

DynamoDB Indexes Deep Dive (GSI vs LSI)

Your DynamoDB table has plenty of write capacity. Your writes are getting throttled anyway.

Nothing is wrong with your table. The problem is a GSI you added eight months ago and forgot about.

AWS has a name for this: GSI back-pressure. If an index can't keep up with the writes flowing into it, DynamoDB throttles the base table until it catches up. Your table is healthy. Your index is the bottleneck. The error lands on the write you just made.

This confuses people because of one wrong assumption almost everyone carries over from SQL.

In Postgres, an index is a structure that lives next to your table and helps the query planner find rows faster. In DynamoDB, a GSI is a separate physical copy of your data, sitting on different hardware, keyed differently.

Not a pointer. A copy.

Once you actually believe that, every strange behavior stops being strange.

Why can't a GSI give you strong consistency? The data is somewhere else. DynamoDB can't promise you're reading the latest write.

Why does one write cost more than one write? Changing an indexed attribute from A to B is two writes, one to delete the old index entry and one to add the new. Five GSIs covering that attribute means six writes for every one you make. You pay for all six.

Why does an index throttle your table? Because it isn't part of your table. It's a second table you didn't realize you were operating.

Now the part that makes the copy model worth it.

If an item is missing the GSI's key attribute, it never enters the index at all. DynamoDB just skips it.

Picture an orders table with 20 million rows. Maybe 1% are still open and need processing. Put an attribute called is_open on only those, leave it off everything else, and build a GSI keyed on it. Your index holds a few thousand rows instead of 20 million. Queries run in single-digit milliseconds, storage costs almost nothing, and you wrote zero filtering logic.

When an order ships, delete the attribute. DynamoDB removes it from the index for you. The index garbage collects itself as work moves through your system.

One trap before you go build this. If you're using LSIs instead, every item that shares a partition key has to fit in 10 GB, and that includes every LSI copy. Three LSIs means four copies of each item counting against the same ceiling. Cross it and DynamoDB starts rejecting writes for that customer. You can't drop an LSI without rebuilding the whole table.

And if you're still gluing strings together like SHIPPED#us-east-1 to fake a composite key, stop. Since November 2025 a GSI can take up to four partition key attributes and four sort key attributes natively. No synthetic fields, no backfills. Sort keys match strictly left to right, so define them in the order you actually query them.

I put the whole mental model into 25 minutes, including the write sharding pattern for when adaptive capacity can't save you: https://youtu.be/xVsEviV2vNA

Top comments (0)