Real scan — anonymized data

3 DynamoDB tables on Pay-Per-Request.
$935/mo more than Provisioned mode.

We scanned a production SaaS platform across 4 AWS regions. The DynamoDB billing mode alone accounted for 80% of the waste. Add Lambda and CloudWatch, and the total hit $1,168/mo.

$1,168/mo in waste. Found in under 2 minutes.

3 DynamoDB tables were running on Pay-Per-Request mode. Their traffic was steady enough for Provisioned capacity with Auto Scaling. That billing mode mismatch cost $935/mo. CostPatrol flagged 26 findings automatically.

Check your account
Total savings
$1,168/mo
$1,168 - $1,293
Findings
26
Rules matched
6
Regions scanned
4

Every finding, with exact fix commands

26 optimization opportunities across 6 rules. Real dollar amounts. Anonymized resource names.

DynamoDB On-Demand to Provisioned Migration
DDB-002 · 3 tables in eu-west-2
$934.67/mo
svc-product-catalog-production
$730.82/mo
eu-west-2 · PAY_PER_REQUEST · Table + GSI1 · Steady traffic pattern
Switch to Provisioned capacity with Auto Scaling (steady traffic)
# Step 1: Switch to provisioned capacity $ aws dynamodb update-table \ --table-name svc-product-catalog-production \ --billing-mode PROVISIONED \ --provisioned-throughput ReadCapacityUnits=461,WriteCapacityUnits=137 \ --global-secondary-index-updates '[{"Update":{"IndexName":"GSI1","ProvisionedThroughput":{"ReadCapacityUnits":205,"WriteCapacityUnits":59}}}]' # Step 2: Configure table read auto scaling $ aws application-autoscaling register-scalable-target \ --service-namespace dynamodb \ --resource-id "table/svc-product-catalog-production" \ --scalable-dimension "dynamodb:table:ReadCapacityUnits" \ --min-capacity 230 --max-capacity 922 $ aws application-autoscaling put-scaling-policy \ --service-namespace dynamodb \ --resource-id "table/svc-product-catalog-production" \ --scalable-dimension "dynamodb:table:ReadCapacityUnits" \ --policy-name "read-scaling" --policy-type TargetTrackingScaling \ --target-tracking-scaling-policy-configuration \ '{"TargetValue":70,"PredefinedMetricSpecification":{"PredefinedMetricType":"DynamoDBReadCapacityUtilization"},"ScaleInCooldown":300,"ScaleOutCooldown":60}' # Step 3: Configure table write auto scaling $ aws application-autoscaling register-scalable-target \ --service-namespace dynamodb \ --resource-id "table/svc-product-catalog-production" \ --scalable-dimension "dynamodb:table:WriteCapacityUnits" \ --min-capacity 68 --max-capacity 274 # Step 4: Repeat for GSI1 (read + write auto scaling) # Same pattern: register scalable target + put scaling policy for each dimension
svc-pricing-ingress-production
$121.92/mo
eu-west-2 · PAY_PER_REQUEST · Write-heavy ingestion table
Switch to Provisioned capacity with Auto Scaling (steady traffic)
$ aws dynamodb update-table \ --table-name svc-pricing-ingress-production \ --billing-mode PROVISIONED \ --provisioned-throughput ReadCapacityUnits=1,WriteCapacityUnits=55 # Then configure auto scaling (same pattern as above) # Write min: 27, max: 110 | Read min: 1, max: 2
svc-event-outbox-production
$81.93/mo
eu-west-2 · PAY_PER_REQUEST · Table + GSI1 · Event-driven outbox pattern
Switch to Provisioned capacity with Auto Scaling (steady traffic)
$ aws dynamodb update-table \ --table-name svc-event-outbox-production \ --billing-mode PROVISIONED \ --provisioned-throughput ReadCapacityUnits=1,WriteCapacityUnits=19 \ --global-secondary-index-updates '[{"Update":{"IndexName":"GSI1","ProvisionedThroughput":{"ReadCapacityUnits":1,"WriteCapacityUnits":19}}}]' # Then configure auto scaling for table + GSI1 # Write min: 9, max: 38 | Read min: 1, max: 2 (both table and GSI)
Lambda ARM64 Migration
LAM-O001 · 14 resources in eu-west-2
$191 - $320/mo
svc-aggregator-production
$173 - $288/mo
eu-west-2 · x86_64 · nodejs20.x · 1024MB · $1,153.42/mo
Migrate to ARM64 (Graviton2) for 20% cost savings
$ aws lambda update-function-configuration \ --function-name svc-aggregator-production \ --architectures arm64
svc-batch-processor-production
$13 - $22/mo
eu-west-2 · x86_64 · nodejs20.x · 1024MB · $88.58/mo
Migrate to ARM64 (Graviton2) for 20% cost savings
$ aws lambda update-function-configuration \ --function-name svc-batch-processor-production \ --architectures arm64
and 12 more x86_64 Lambda functions — $5.56 - $9.28/mo combined
CloudWatch Metric Streams Unfiltered
CW-O003 · 1 resource in eu-west-2
$29.34/mo
Monitoring-Metric-Stream--eu-west-2
$29.34/mo
eu-west-2 · $48.90/mo · Streaming all namespaces to monitoring provider
Add include filters to restrict to namespaces you actually consume
# Add namespace filters to stop streaming metrics you don't use $ aws cloudwatch put-metric-stream \ --name Monitoring-Metric-Stream--eu-west-2 \ --firehose-arn arn:aws:firehose:eu-west-2:xxxxxxxxxxxx:deliverystream/Monitoring-Delivery-Stream--eu-west-2 \ --output-format json \ --include-filters '[{"Namespace":"AWS/Lambda"},{"Namespace":"AWS/DynamoDB"},{"Namespace":"AWS/ApiGateway"}]'
Lambda Memory Right-Sizing
LAM-O002 · 6 resources in eu-west-2
$14.69/mo
svc-perf-upsert-production
$6.51/mo
eu-west-2 · 1024MB allocated · 359MB peak usage · $13.02/mo
Reduce memory from 1024MB to 512MB (30% buffer above peak usage)
$ aws lambda update-function-configuration \ --function-name svc-perf-upsert-production \ --memory-size 512
svc-perf-sync-production
$5.63/mo
eu-west-2 · 1024MB allocated · 327MB peak usage · $11.26/mo
Reduce memory from 1024MB to 512MB (30% buffer above peak usage)
$ aws lambda update-function-configuration \ --function-name svc-perf-sync-production \ --memory-size 512
and 4 more over-provisioned Lambda functions — $2.55/mo combined
Unused API Gateway APIs
APIGW-O002 · 1 resource in eu-west-2
$0.00/mo
svc-api-production
$0.00/mo
eu-west-2 · REST API · Zero requests in past 30 days
Delete unused API Gateway (no cost savings but reduces attack surface)
$ aws apigateway delete-rest-api --rest-api-id xxxxxxxxxxxx

What AWS Cost Explorer misses

AWS Cost Explorer
Shows total DynamoDB spend — can't tell you which billing mode is optimal
Tells you "DynamoDB costs went up" — not that on-demand is 6.5x more expensive than provisioned
Cannot analyze read/write patterns to recommend provisioned capacity
No auto scaling configuration — you're on your own
CostPatrol
Analyzes actual read/write patterns per table over 30 days
"3 tables on Pay-Per-Request — provisioned mode saves $935/mo"
Calculates exact provisioned capacity numbers from real usage data
Complete auto scaling commands with min/max and target utilization

AWS tells you DynamoDB costs went up. CostPatrol tells you that 3 tables on Pay-Per-Request with steady traffic should be on Provisioned mode, saving $935/mo — and gives you the exact capacity numbers and auto scaling commands to make the switch.

You've been meaning to do this.

It takes 2 minutes. If there's nothing to find, you lost a coffee break.