These rules identify DynamoDB tables with stale data and provisioned tables missing auto-scaling, both common sources of unnecessary DynamoDB spend.
| Rule ID | Scan Type | Name |
|---|---|---|
| CLDBRN-AWS-DYNAMODB-1 | Discovery | DynamoDB Table Stale Data |
| CLDBRN-AWS-DYNAMODB-2 | Discovery | DynamoDB Table Without Autoscaling |
CLDBRN-AWS-DYNAMODB-1
DynamoDB Table Stale Data
Scan type: Discovery
What it checks
Flags DynamoDB tables whose data has not changed for more than 90 days, based on the table's latest stream label timestamp. Tables that store data nobody reads or writes are candidates for archival or deletion.
Tables without DynamoDB Streams enabled are skipped because there's no reliable timestamp to measure staleness.
Why it matters
DynamoDB charges for provisioned or on-demand read/write capacity and for stored data. A table sitting idle with no writes for 90+ days is still paying for storage (and capacity, if provisioned). If the data is no longer needed, deleting or archiving the table to S3 eliminates ongoing charges.
What triggers a finding
The table has DynamoDB Streams enabled, and the latestStreamLabel timestamp is more than 90 days in the past.
How to remediate
- Check whether any application still reads from the table. CloudWatch's
ConsumedReadCapacityUnitsmetric can confirm if reads are happening - If the table is no longer needed, export it to S3 for archival and delete it:
aws dynamodb export-table-to-point-in-time \
--table-arn arn:aws:dynamodb:us-east-1:123456789012:table/my-table \
--s3-bucket my-archive-bucket \
--s3-prefix dynamodb-exports/
aws dynamodb delete-table --table-name my-table
- If the data is still needed but access is infrequent, switch the table to on-demand capacity mode to eliminate provisioned throughput charges during idle periods
CLDBRN-AWS-DYNAMODB-2
DynamoDB Table Without Autoscaling
Scan type: Discovery
What it checks
Flags provisioned-capacity DynamoDB tables that do not have Application Auto Scaling configured for table-level read and write capacity. Without auto-scaling, provisioned tables pay for a fixed throughput regardless of actual traffic.
Tables using on-demand (pay-per-request) billing are not flagged because they scale automatically.
Why it matters
A provisioned DynamoDB table without auto-scaling pays for its fixed capacity around the clock. If traffic drops to zero at night but the table is provisioned for peak daytime load, you're paying for unused capacity every off-peak hour. Auto-scaling adjusts provisioned capacity based on actual utilization, keeping costs proportional to demand.
What triggers a finding
All of the following must be true:
- The table's billing mode is not
PAY_PER_REQUEST(i.e., it uses provisioned capacity) - The table does not have a table-level read scalable target registered with Application Auto Scaling
- The table does not have a table-level write scalable target registered with Application Auto Scaling
GSI-level auto-scaling targets are not considered for this rule, only table-level targets.
How to remediate
Register the table with Application Auto Scaling and create scaling policies:
# Register read capacity target
aws application-autoscaling register-scalable-target \
--service-namespace dynamodb \
--resource-id "table/my-table" \
--scalable-dimension "dynamodb:table:ReadCapacityUnits" \
--min-capacity 5 \
--max-capacity 1000
# Register write capacity target
aws application-autoscaling register-scalable-target \
--service-namespace dynamodb \
--resource-id "table/my-table" \
--scalable-dimension "dynamodb:table:WriteCapacityUnits" \
--min-capacity 5 \
--max-capacity 1000
Alternatively, consider switching to on-demand billing if your traffic is unpredictable. On-demand costs more per request but eliminates the risk of over-provisioning entirely.
See Also
- CLI discover command - scan live DynamoDB tables
- SDK Reference - run discovery programmatically