The most surprising thing about DynamoDB consistency is that you’re probably paying for strong consistency when you don’t need it.

Let’s see it in action. Imagine an e-commerce application where users browse products, add them to a cart, and then check out.

Here’s a simplified representation of how item data might look in DynamoDB:

{
  "productId": "PROD123",
  "name": "Super Widget",
  "price": 29.99,
  "stockCount": 150
}

When a user views a product page, they just need to see the product information, including its current stock. They aren’t making a purchase decision based on that exact moment’s stock count. If they see stockCount: 149 and then it was actually 148 a millisecond later, it doesn’t matter. This is a perfect use case for eventual consistency. A Scan or Query operation with default settings will give you eventually consistent reads.

aws dynamodb scan \
    --table-name Products \
    --filter-expression "productId = :pid" \
    --expression-attribute-values '{
        ":pid": {"S": "PROD123"}
    }'

Now, consider the checkout process. When a user clicks "Place Order," you must know the exact, current stock count to prevent overselling. If the application reads stockCount: 10, and then another user’s order also reads stockCount: 10 and both proceed, you’ve sold 2 items when you only had 10. This is where strong consistency is critical. You need to read the item, decrement the stock, and update it atomically.

For this, you’d use a GetItem operation with the ConsistentRead parameter set to true:

aws dynamodb get-item \
    --table-name Products \
    --key '{
        "productId": {"S": "PROD123"}
    }' \
    --consistent-read

This ensures that the data you retrieve is the most up-to-date version available. If you need to perform a read-modify-write operation, like decrementing stock, you’d typically use a TransactWriteItems API call. This API call handles the atomicity and consistency for you across multiple items or tables. If you were just updating a single item’s stock, you could use UpdateItem with a conditional expression to ensure you only update if the stock is greater than zero.

The mental model here is simple: reads are either eventually consistent (default, faster, cheaper) or strongly consistent (guaranteed up-to-date, slower, more expensive). Writes are always strongly consistent – when you write data, subsequent reads will eventually reflect that write. The default for reads is eventual.

This distinction matters because strongly consistent reads cost twice as much as eventually consistent reads. If your application can tolerate slightly stale data for certain read operations (like displaying product details or aggregated counts), switching to eventual consistency for those reads can significantly reduce your DynamoDB costs without impacting user experience. You only pay the premium for strong consistency when the integrity of the data at that precise moment is paramount, such as during financial transactions or inventory management critical paths.

The true power of DynamoDB’s consistency model lies in its ability to offer both, allowing you to optimize for performance, cost, and data integrity on a per-operation basis. Most developers default to strong consistency for all reads out of caution, but understanding the trade-offs allows for significant cost savings and performance gains.

The next hurdle is understanding how DynamoDB’s Global Tables handle consistency across multiple AWS regions.

Want structured learning?

Take the full Dynamodb course →