Home / AWS

AWSHow-toIntermediate

Optimization: DynamoDB cost - capacity mode, table class, TTL and index design

DynamoDB bills for reads, writes, storage and every index. Choose on-demand or provisioned with auto scaling from real traffic, switch storage-heavy tables to Standard-IA, expire data with TTL, trim GSI projections and item sizes, and cache hot reads.

Deepak Bhardwaj3 min read

Applies toAmazon DynamoDB (on-demand and provisioned capacity, Standard and Standard-IA table classes, GSIs, TTL, DAX)

Where the money goes

Component Driven by
Writes Item size (1 KB write units) × writes, × every GSI the item projects into
Reads Item size (4 KB read units) × reads; eventually consistent reads cost half
Storage Table + index size
Extras Backups, global table replication, streams, exports

Check Cost Explorer by usage type for each table (tags help) to know which applies.

1. On-demand or provisioned?

Traffic Mode
Unpredictable, spiky, new tables, low volume On-demand
Steady and predictable, high volume Provisioned + auto scaling (+ reserved capacity for the baseline)

Compare: last month's consumed RCU/WCU per hour (CloudWatch ConsumedReadCapacityUnits/ConsumedWriteCapacityUnits) priced as provisioned at ~70% target utilisation vs actual on-demand cost. Switching modes is limited to a few times per 24 hours, so test on one table first.

aws dynamodb update-table --table-name orders --billing-mode PROVISIONED \
  --provisioned-throughput ReadCapacityUnits=200,WriteCapacityUnits=100
aws application-autoscaling register-scalable-target --service-namespace dynamodb \
  --resource-id table/orders --scalable-dimension dynamodb:table:WriteCapacityUnits --min-capacity 50 --max-capacity 1000

Add a target-tracking policy (~70%) for each dimension and for each GSI.

2. Table class: Standard-IA for storage-heavy tables

Standard-Infrequent Access lowers storage price and raises read/write price. It pays off when storage is the dominant cost (old orders, history, audit data that's rarely read):

aws dynamodb update-table --table-name order-history --table-class STANDARD_INFREQUENT_ACCESS

3. Expire data with TTL

aws dynamodb update-time-to-live --table-name sessions \
  --time-to-live-specification "Enabled=true, AttributeName=expiresAt"

expiresAt is a Unix epoch seconds number. TTL deletes are free (no write units consumed) and happen in the background, typically within a few days of expiry, so filter expired items in queries if exactness matters. Stream the deletions to S3 if you need an archive.

4. Index design

  • Every GSI adds write cost for every item write that touches projected attributes. Remove unused GSIs (check ConsumedReadCapacityUnits on the index).
  • Use KEYS_ONLY or INCLUDE projections instead of ALL when queries need few attributes.
  • Sparse indexes: only items with the index key attribute are indexed. Useful for "open orders" style queries.

5. Item size and access patterns

  • Large items cost more on every read/write. Move big blobs to S3 and store a pointer.
  • Shorter attribute names reduce size on very large tables.
  • ProjectionExpression reduces network transfer but not read units (those are based on the full item size). If rarely used large attributes inflate every read, split them into a separate item.
  • Batch and query instead of scans; scans read (and bill) the whole table.

6. Cache hot reads

DAX or an application cache (ElastiCache) for read-heavy, repeated keys: product catalogues, configuration, session lookups. Check consistency needs; DAX serves eventually consistent reads.

7. Other line items

  • Point-in-time recovery and on-demand backups: keep, but expire old on-demand backups.
  • Global tables: replicated writes cost in every region. Only replicate tables that need multi-region.
  • Streams consumers: filter events in Lambda event source mappings.

Tip

Look at the write cost per table first. It's often multiplied by GSIs nobody remembers creating. Dropping one unused GSI with an ALL projection can cut a table's write bill substantially.

Checklist

  • Cost split by reads, writes, storage, extras per table
  • Capacity mode chosen from consumed capacity data
  • Standard-IA for storage-dominated tables
  • TTL on expiring data
  • Unused GSIs removed; projections trimmed
  • Large attributes moved to S3; scans eliminated
  • Caching for hot keys