
Aws Billing And Cost Management
- 4.3k installs
- 2.2k repo stars
- Updated August 4, 2026
- aws/agent-toolkit-for-aws
aws-billing-and-cost-management is a skill for AWS cost analysis, budgets, savings plans, right-sizing, and CUR Athena queries.
About
AWS Billing and Cost Management encodes expertise for analyzing, optimizing, and managing AWS spend across Cost Explorer, Budgets, Billing Views, Compute Optimizer, Cost Optimization Hub, Savings Plans, Reserved Instances, CUR 2.0 Athena queries, anomaly detection, and Free Tier monitoring. Critical rules require determining the current date before any Cost Explorer or Budgets API call and never performing arithmetic in prose; scripts must compute sums, averages, and percentages deterministically. Decision guide maps questions to references such as cost-explorer for spend breakdowns, pricing-lookup for service rates, optimization hub for savings starting point, and cost-audit for seven-step bill reduction workflow. Billing Views scope analysis via list-billing-views and --billing-view-arn on supported CE and budget APIs. Compute Optimizer needs enrollment via update-enrollment-status Active before recommendations. Common traps include RECORD_TYPE versus CHARGE_TYPE filters, Price List service codes differing from CE names, and hourly granularity requiring CE preferences. AWS MCP server is recommended for sandboxed execution when available.
- Always verify current date before Cost Explorer calls.
- Deterministic scripts required for all cost math.
- Decision guide maps questions to CE, COH, SP, RI, and CUR tools.
- Billing view ARN scoping for CE and budget APIs.
- Seven-step cost audit workflow reference.
Aws Billing And Cost Management by the numbers
- 4,295 all-time installs (skills.sh)
- +514 installs in the week ending Aug 5, 2026 (Skillselion tracking)
- Ranked #126 of 1,039 Cloud & Infrastructure skills by installs in the Skillselion catalog
- Security screen: MEDIUM risk (skills.sh audit)
- Data as of Aug 5, 2026 (Skillselion catalog sync)
aws-billing-and-cost-management capabilities & compatibility
- Capabilities
- cost explorer query patterns with correct filter · budget creation and billing view scoping · savings plans and reserved instance evaluation · compute optimizer enrollment and recommendations · cur athena query guidance · deterministic calculation enforcement
- Works with
- aws
- Use cases
- devops · data analysis
- Pricing
- Bring your own API key
What aws-billing-and-cost-management says it does
you MUST determine the current date
npx skills add https://github.com/aws/agent-toolkit-for-aws --skill aws-billing-and-cost-managementAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 4.3k |
|---|---|
| repo stars | ★ 2.2k |
| Security audit | 2 / 3 scanners passed |
| Last updated | August 4, 2026 |
| Repository | aws/agent-toolkit-for-aws ↗ |
How do I analyze AWS spend, find savings, and set budgets without incorrect date or math errors?
Analyze AWS costs, budgets, Savings Plans, right-sizing, CUR Athena queries, and billing view scoped spend.
Who is it for?
Engineers and FinOps owners investigating AWS bills, spikes, commitments, and idle resources.
Skip if: Skip for non-AWS clouds, invoice accounting outside AWS APIs, or application feature development.
When should I use this skill?
User analyzes AWS bills, cost spikes, Savings Plans, right-sizing, budgets, CUR, or billing views.
What you get
Script-verified cost breakdown, savings recommendations, or budget configuration for the correct time range.
- cost analysis summary
- right-sizing recommendations
- budget and savings plan guidance
By the numbers
- Version 1 AWS Agent Toolkit skill
- Covers EC2, Lambda, RDS, EBS right-sizing via Compute Optimizer
Files
Billing and Cost Management
Overview
Analyze, optimize, and manage AWS costs. This skill encodes domain expertise from AWS's cost management products — gotchas, correct API usage patterns, and optimization workflows that models frequently get wrong.
Usage
Use this skill when:
- Analyzing AWS spending, cost trends, or cost breakdowns
- Setting up or managing budget alerts
- Evaluating Savings Plans or Reserved Instance purchases
- Right-sizing EC2, Lambda, RDS, or EBS resources
- Looking up AWS service pricing
- Running cost audits or investigating cost spikes
- Querying CUR data with Athena
- Scoping cost analysis to a specific billing view
- Checking Free Tier usage
Core Concepts
- Cost Explorer — query cost/usage data by service, account, tag, or time range
- Budgets — set spending thresholds with alerts; supports billing view scoping
- Billing Views — scope cost data to a subset of billing (custom view, billing group, or primary)
- Compute Optimizer — right-sizing recommendations for EC2, Lambda, EBS, RDS
- Cost Optimization Hub — aggregated savings recommendations across services
- Savings Plans / Reserved Instances — commitment-based discounts
- CUR 2.0 — detailed line-item billing data queryable via Athena
Recommended setup: Use the AWS MCP server for sandboxed execution, audit logging, and enterprise controls. See: https://docs.aws.amazon.com/aws-mcp/
Without AWS MCP: All commands use standard AWS CLI syntax and work with any agent that has CLI access.
Critical Rule: Always Check the Current Date
Before making ANY Cost Explorer, Budgets, or Savings Plans API call, you MUST determine the current date. Use a tool to get the current date and time — do NOT assume or guess the year. LLMs frequently default to dates from their training data instead of the actual current date, producing analyses of stale data that appear correct but are completely wrong.
Critical Rule: Deterministic Calculations
You MUST NEVER perform numerical calculations (sums, averages, percentages, comparisons, counts, min/max) by reasoning in your response. LLM arithmetic is unreliable and produces wrong answers on cost data.
You MUST ALWAYS use a script or calculator tool for any math on data returned from API calls. Write a Python script that performs the calculation and prints the result. If the AWS MCP server's run_script tool is available, use it. Otherwise, run the script locally.
Read references/deterministic-calculations.md for patterns and examples.
Decision Guide
| Question | Tool | Reference |
|---|---|---|
| What am I spending? Where are costs going up? | Cost Explorer | references/cost-explorer.md |
| How much does a service cost? | Price List API | references/pricing-lookup.md |
| Where can I save money? (start here) | Cost Optimization Hub | references/cost-optimization-hub.md |
| Should I buy Savings Plans? | CE SP Recommendations | references/savings-plans.md |
| Should I buy Reserved Instances? | CE RI Recommendations | references/reserved-instances.md |
| Deep-dive on a specific EC2/Lambda/EBS/RDS rec? | Compute Optimizer | references/ec2-rightsizing.md, references/lambda-optimization.md, references/rds-optimization.md, references/ebs-optimization.md |
| How do I set up budget alerts? | Budgets | references/budgets.md |
| What's causing a cost spike? | Cost Anomaly Detection | references/cost-explorer.md |
| Am I within Free Tier? | Free Tier API | references/free-tier.md |
| How do I reduce my bill? | Cost Audit workflow | references/cost-audit.md |
| How do I query detailed billing data? | CUR 2.0 + Athena | references/cur-athena.md |
| How do I optimize specific services? | Per-service patterns | references/service-optimization.md |
| How do I scope costs to a billing view? | Billing Views | See Billing Views below |
Common Tasks
Analyze costs by service
aws ce get-cost-and-usage \
--time-period Start=2026-03-01,End=2026-04-01 \
--granularity MONTHLY \
--metrics UnblendedCost \
--group-by Type=DIMENSION,Key=SERVICEDefault to UnblendedCost. Exclude Credits/Refunds with --filter '{"Not":{"Dimensions":{"Key":"RECORD_TYPE","Values":["Credit","Refund"]}}}'. End date is exclusive.
Run a cost audit
Read references/cost-audit.md for the full 7-step workflow: top cost drivers → month-over-month comparison → optimization recommendations → idle resources → commitment coverage → per-service quick wins → report.
Get right-sizing recommendations
Compute Optimizer requires opt-in first: aws compute-optimizer update-enrollment-status --status Active. Then read references/ec2-rightsizing.md for EC2 or the relevant resource-specific reference.
Look up service pricing
Read references/pricing-lookup.md for service codes and attribute filters. Common trap: Price List API service codes differ from Cost Explorer service names.
Billing Views
A billing view scopes cost and usage data to a specific slice of an account's billing (e.g., a billing group, custom view, or the default primary view). When the user wants to analyze costs through a particular billing view, add --billing-view-arn to supported API calls.
Discover available billing views
aws billing list-billing-views \
--billing-view-types PRIMARY CUSTOM BILLING_GROUPRequires billing:ListBillingViews permission.
Use a billing view with Cost Explorer
aws ce get-cost-and-usage \
--time-period Start=2026-03-01,End=2026-04-01 \
--granularity MONTHLY \
--metrics UnblendedCost \
--group-by Type=DIMENSION,Key=SERVICE \
--billing-view-arn arn:aws:billing::ACCOUNT_ID:billingview/BILLING_VIEW_IDCreate a budget scoped to a billing view
In the --budget JSON, include the BillingViewArn field:
aws budgets create-budget --account-id ACCOUNT_ID \
--budget '{
"BudgetName": "TeamX-Monthly",
"BudgetLimit": {"Amount": "1000", "Unit": "USD"},
"TimeUnit": "MONTHLY",
"BudgetType": "COST",
"BillingViewArn": "arn:aws:billing::ACCOUNT_ID:billingview/BILLING_VIEW_ID"
}'API support for --billing-view-arn
Supports --billing-view-arn | Does NOT support it |
|---|---|
ce get-cost-and-usage | ce get-reservation-coverage |
ce get-cost-and-usage-with-resources | ce get-reservation-utilization |
ce get-cost-forecast | ce get-savings-plans-coverage |
ce get-usage-forecast | ce get-savings-plans-utilization |
ce get-dimension-values | |
ce get-tags | |
ce get-cost-comparison-drivers | |
budgets create-budget (in budget JSON) |
Troubleshooting
| Error | Cause | Fix |
|---|---|---|
ValidationException on Cost Explorer | Wrong dimension key (e.g., CHARGE_TYPE instead of RECORD_TYPE) | Use RECORD_TYPE for charge type filtering |
| Empty results with filter | Filter value doesn't match exactly | Call GetDimensionValues first to get valid values |
AccessDeniedException on hourly data | Hourly granularity not enabled | Enable in Cost Explorer preferences |
Account not registered on Compute Optimizer | Not opted in | Run update-enrollment-status --status Active |
| Budgets API fails outside us-east-1 | Budgets requires us-east-1 | Set --region us-east-1 |
Cost Explorer Total empty with GroupBy | By design — totals excluded when grouping | Make separate call without GroupBy, or sum grouped results using a script |
AccessDeniedException on list-billing-views | Missing permission | User needs billing:ListBillingViews permissions |
ValidationException with --billing-view-arn | API doesn't support billing views, or malformed ARN | Check the API support table above; ARN format is arn:aws:billing::ACCOUNT_ID:billingview/VIEW_ID |
Budget shows UNHEALTHY health status | Billing view access revoked or view deleted | Check HealthStatus.StatusReason in describe-budget output; ensure billing:GetBillingViewData is granted |
Additional Resources
- AWS Cost Management User Guide: https://docs.aws.amazon.com/cost-management/
- AWS Pricing Calculator: https://calculator.aws/
- Compute Optimizer User Guide: https://docs.aws.amazon.com/compute-optimizer/
- Well-Architected Cost Optimization Pillar: https://docs.aws.amazon.com/wellarchitected/latest/cost-optimization-pillar/
AWS Budgets
Pricing note: All prices shown are approximate as of early 2026 and may change. Always verify current pricing before reporting to users.
Budget Types
| Type | Use Case |
|---|---|
| COST | Track spend against dollar amount (default) |
| USAGE | Track usage quantity (e.g., EC2 hours) |
| RI_UTILIZATION | Alert when RI utilization drops below threshold |
| SAVINGS_PLANS_UTILIZATION | Alert when SP utilization drops |
Use FORECASTED notification type to catch runaway costs before they hit threshold.
Create Budget with Alerts
aws budgets create-budget --region us-east-1 \
--account-id 123456789012 \
--budget '{"BudgetName":"Monthly-Total","BudgetLimit":{"Amount":"1000","Unit":"USD"},"TimeUnit":"MONTHLY","BudgetType":"COST"}' \
--notifications-with-subscribers '[
{"Notification":{"NotificationType":"ACTUAL","ComparisonOperator":"GREATER_THAN","Threshold":80,"ThresholdType":"PERCENTAGE"},"Subscribers":[{"SubscriptionType":"EMAIL","Address":"team@example.com"}]},
{"Notification":{"NotificationType":"FORECASTED","ComparisonOperator":"GREATER_THAN","Threshold":100,"ThresholdType":"PERCENTAGE"},"Subscribers":[{"SubscriptionType":"SNS","Address":"arn:aws:sns:us-east-1:123456789012:budget-alerts"}]}
]'Each threshold is a separate entry in NotificationsWithSubscribers. Do NOT put multiple thresholds in one notification object.
Tag-Based Budget
Use CostFilters with TagKeyValue key and tag-key$tag-value format:
"CostFilters": {"TagKeyValue": ["user:Environment$production"]}Budget Actions
Automatically apply IAM deny policies or SCPs when threshold is breached. Use for hard spending limits. Budget Actions cannot directly stop EC2 instances — use SNS → Lambda for custom actions.
Gotchas
- Budgets API requires `us-east-1` region for global billing data
- Monitoring-only budgets (no actions) are free — unlimited
- First 2 action-enabled budgets are free; additional action-enabled budgets cost $0.10/day each
- Budget Reports cost $0.01 per report delivered
- Budget alerts evaluate once per day — up to 24-hour delay, not real-time
FORECASTEDalerts use ML-based forecasting — useful for catching runaway costs early- Budget Actions are powerful but dangerous — test in non-prod first
- RI/SP utilization budgets default to 100% — set to 80% for practical alerting
Cost Audit Workflow
Pricing note: All prices shown are us-east-1 approximate as of early 2026. Prices vary by region and may change. Always verify current pricing via the Price List API before reporting to users.
Execute when a user asks to audit costs, reduce their bill, or find savings. Prioritize: immediate (delete unused) → short-term (right-size, configure) → long-term (commitments).
Step 1: Top Cost Drivers
aws ce get-cost-and-usage \
--time-period Start=2026-03-01,End=2026-04-01 \
--granularity MONTHLY --metrics UnblendedCost \
--group-by Type=DIMENSION,Key=SERVICEStep 2: Month-over-Month Comparison
Run the same query for the previous month. Calculate percent change per service using a script (see references/deterministic-calculations.md). Flag services with >20% increase.
Step 3: Optimization Recommendations (Start with COH)
Use Cost Optimization Hub to get all recommendations, prioritized by savings. COH consolidates and de-duplicates across Compute Optimizer, Cost Explorer rightsizing, SPs, RIs, and idle resources. See references/cost-optimization-hub.md for CLI commands and correct parameter syntax.
Step 4: Find Idle/Unused Resources
# Unattached EBS volumes
aws ec2 describe-volumes --filters Name=status,Values=available \
--query "Volumes[].{ID:VolumeId,Size:Size,Type:VolumeType}" --output table
# Unattached Elastic IPs (~$3.65/month each — all public IPv4 addresses cost $0.005/hr whether in-use or idle)
aws ec2 describe-addresses \
--query "Addresses[?!InstanceId && !NetworkInterfaceId]"Step 5: Check Commitment Coverage
aws ce get-savings-plans-coverage \
--time-period Start=2026-03-01,End=2026-04-01 --granularity MONTHLY
aws ce get-savings-plans-utilization \
--time-period Start=2026-03-01,End=2026-04-01 --granularity MONTHLY
# Reserved Instance coverage & utilization
aws ce get-reservation-coverage \
--time-period Start=2026-03-01,End=2026-04-01 --granularity MONTHLY
aws ce get-reservation-utilization \
--time-period Start=2026-03-01,End=2026-04-01 --granularity MONTHLYStep 6: Per-Service Quick Wins
# Log groups without retention
aws logs describe-log-groups \
--query "logGroups[?!retentionInDays].{Name:logGroupName,StoredBytes:storedBytes}" --output table
# Lambda functions still on x86_64
aws lambda list-functions \
--query "Functions[?Architectures[0]=='x86_64'].{Name:FunctionName,Memory:MemorySize}" --output table
# Existing S3 gateway endpoints (cross-reference against all VPCs to find missing ones)
aws ec2 describe-vpc-endpoints --filters Name=service-name,Values=*s3* \
--query "VpcEndpoints[].{VPC:VpcId,Service:ServiceName}"
# Existing DynamoDB gateway endpoints
aws ec2 describe-vpc-endpoints --filters Name=service-name,Values=*dynamodb* \
--query "VpcEndpoints[].{VPC:VpcId,Service:ServiceName}"Step 7: Generate Report
Structure findings as: Top Cost Drivers (table) → Immediate Savings (delete unused) → Short-Term (right-size, configure) → Long-Term (commitments) → Estimated Total Monthly Savings.
Label all figures as ACTUAL DATA (from API) or ESTIMATED SAVINGS (calculated via script). NEVER hallucinate cost numbers.
Cost Explorer API Patterns
Pricing note: All prices shown are approximate as of early 2026 and may change. Always verify current pricing before reporting to users.
Defaults
- Metric:
UnblendedCost(single account). UseAmortizedCostwhen customer has SPs/RIs. - Exclude Credits/Refunds:
--filter '{"Not":{"Dimensions":{"Key":"RECORD_TYPE","Values":["Credit","Refund"]}}}' - End date is exclusive:
Start=2026-03-01,End=2026-04-01returns all of March. - Max 2 GroupBy dimensions per request.
Critical Gotchas
EC2 service names: EC2 charges split into two services. "Amazon Elastic Compute Cloud - Compute" is instance usage. "EC2 - Other" (with spaces around hyphen) is NAT Gateway, EBS, data transfer. WRONG: "EC2-Other", "EC2Other". If "EC2 - Other" returns $0, call GetDimensionValues to confirm the exact service name, then retry.
RECORD_TYPE not CHARGE_TYPE: The dimension for charge type filtering is RECORD_TYPE. Using CHARGE_TYPE throws ValidationException.
Empty Total with GroupBy: By design — Total is empty when GroupBy is used. Sum grouped results using a script (see references/deterministic-calculations.md), or make a separate call without GroupBy.
Filter validation: Cost Explorer does not distinguish between valid filters with no data and invalid filters. If a filter returns no results, call GetDimensionValues to verify the filter value exists.
API cost: Each GetCostAndUsage or GetCostForecast call costs $0.01. Cache results.
Hourly granularity: Requires opt-in in Cost Explorer preferences. Only available for past 14 days. Hourly + resource-level only works for EC2 Compute.
Tags take 24 hours to appear after activation, and only for resources that incurred costs after activation — not retroactive.
Usage Quantity Analysis
When using USAGE_QUANTITY metric:
- MUST group by usage type OR filter for usage types with the same unit (e.g., GB-month)
- NEVER aggregate different usage units (GB-months + instance-hours)
- If API returns usage units of
"NA", multiple units were aggregated — discard these results
Data Transfer Analysis
Data transfer costs in Cost Explorer are spread across multiple usage type patterns. Use a script with regex for accurate filtering — do NOT rely on broad keyword matching (Bytes, Transfer) as it produces many false positives.
Core data transfer (product family "Data Transfer" in CUR):
DataTransfer-*-Bytes— Internet ingress/egress, intra-region cross-AZ*-AWS-Out-Bytes,*-AWS-In-Bytes— inter-region transfer*-Bytes-Internet,*-Bytes-AWS— Global AcceleratorCloudFront-*-Bytes— CloudFront to/from origin*-DataXfer-*— Direct Connect*-ABytes-*— S3 Transfer Acceleration
Networking data processing (billed under respective services, not under "Data Transfer"):
*-NatGateway-Bytes— per-byte NAT Gateway processing (service:EC2 - Other)*-VpcEndpoint-Bytes— per-byte VPC Endpoint / PrivateLink processing (service:Amazon Virtual Private Cloud)*-TransitGateway-Bytes— per-byte Transit Gateway processing (service:Amazon Virtual Private Cloud)*-DataProcessing-Bytes— per-byte processing, but source varies by service:Elastic Load Balancing→ NLB/GLB data processing (networking, include)AmazonCloudWatch→ VPC Flow Logs processing (observability, exclude)- Other services → check context before including
Group by both SERVICE and USAGE_TYPE to disambiguate DataProcessing-Bytes. Only include it when the service is Elastic Load Balancing.
Networking infrastructure (hourly charges for networking resources that facilitate data movement):
*-NatGateway-Hours— NAT Gateway hourly charge*-VpcEndpoint-Hours— VPC Endpoint hourly charge*-TransitGateway-Hours— Transit Gateway attachment hourly chargeGlobalAccelerator*— Global Accelerator hourly + data transfer*-LCUUsage— ALB capacity units
Include both networking categories in your analysis as separate sections — customers asking about "data transfer costs" often want to see the full networking picture, not just per-byte charges.
NOT data transfer (common false positives): Ingestion-Bytes (CloudWatch Logs), PaidEventsAnalyzed-Bytes (CloudTrail), QueryScanned-Bytes (Logs Insights), VendedLog-Bytes, LambdaNetworkLogsAnalyzed-Bytes, Select-Scanned-Bytes/Select-Returned-Bytes (S3 Select).
Script: Query GetCostAndUsage grouped by both SERVICE and USAGE_TYPE (max 2 GroupBy per request), then filter:
import re
TRANSFER_RE = re.compile(r'DataTransfer|AWS-(In|Out)-Bytes|Bytes-(Internet|AWS)|CloudFront-.*-Bytes|DataXfer|-ABytes-')
NETWORKING_PROCESSING_RE = re.compile(r'NatGateway-Bytes|VpcEndpoint-Bytes|TransitGateway-Bytes')
NETWORKING_INFRA_RE = re.compile(r'NatGateway-Hours|VpcEndpoint-Hours|TransitGateway-Hours|GlobalAccelerator|LCUUsage')
# Each group has keys [service, usage_type] and cost
for service, usage_type, cost in results:
if TRANSFER_RE.search(usage_type):
pass # Core data transfer
elif NETWORKING_PROCESSING_RE.search(usage_type):
pass # Networking data processing
elif 'DataProcessing-Bytes' in usage_type and service == 'Elastic Load Balancing':
pass # ELB data processing (networking) — exclude CloudWatch/other services
elif NETWORKING_INFRA_RE.search(usage_type):
pass # Networking infrastructure (hourly)
# Everything else: not data transferUsage types with no regional prefix may be us-east-1 or global. The "EU" prefix means eu-west-1.
For deeper analysis with resource-level detail, recommend CUR + Athena with product_family = 'Data Transfer'. Reference: https://aws.amazon.com/blogs/networking-and-content-delivery/understand-aws-data-transfer-details-in-depth-from-cost-and-usage-report-using-athena-query-and-quicksight/
Resource-Level Analysis
Use GetCostAndUsageWithResources (not GetCostAndUsage) for individual resource costs.
- Only available for past 14 days
- Requires opt-in via Cost Management Preferences (per-service)
- MUST include a filter (typically by service) and group by
RESOURCE_ID - Resources without opt-in show as
"No Resource ID"
Date Handling
- If user says "last month" without a year, use the most recent completed month
- ALWAYS check the current date before querying. Use
dateor equivalent to confirm the current year and month. Models frequently default to dates from training data. An analysis of "last month" using the wrong year will return real data that looks plausible but is entirely stale — the most dangerous kind of error. - NEVER compare a complete month to a partial current month without calculating daily averages
- Cost data has ~24-hour delay — current day data is estimated
Common CLI Commands
# Monthly cost by service
aws ce get-cost-and-usage \
--time-period Start=2026-03-01,End=2026-04-01 \
--granularity MONTHLY --metrics UnblendedCost \
--group-by Type=DIMENSION,Key=SERVICE
# Cost forecast
aws ce get-cost-forecast \
--time-period Start=2026-04-02,End=2026-05-01 \
--metric UNBLENDED_COST --granularity MONTHLY
# Get valid dimension values
aws ce get-dimension-values \
--time-period Start=2026-03-01,End=2026-04-01 \
--dimension SERVICE
# Cost anomaly detection
aws ce get-anomalies \
--date-interval '{"StartDate":"2026-03-01","EndDate":"2026-04-01"}'Cost Optimization Hub
Cost Optimization Hub (COH) is the recommended starting point for finding savings. It consolidates and de-duplicates recommendations from multiple sources (Compute Optimizer, Cost Explorer rightsizing, Savings Plans, Reserved Instances, idle resources) into a single prioritized view with estimated savings.
Why Start Here
- De-duplication: A single EC2 instance may appear in Compute Optimizer (right-size), Cost Explorer (RI recommendation), AND idle resource detection. COH consolidates these into one recommendation with the highest-impact action.
- Prioritization: Recommendations ranked by estimated monthly savings across all services and recommendation types.
- Aggregation: Single API to get all optimization opportunities across the account or organization.
CLI Commands
# List recommendation summaries grouped by resource type
aws cost-optimization-hub list-recommendation-summaries \
--group-by ResourceType
# List recommendations sorted by savings (highest first)
aws cost-optimization-hub list-recommendations \
--order-by '{"dimension":"EstimatedMonthlySavings","order":"Desc"}' \
--max-results 20
# Get details for a specific recommendation
aws cost-optimization-hub get-recommendation \
--recommendation-id <id>
# Filter by resource type
aws cost-optimization-hub list-recommendations \
--filter '{"resourceTypes":["Ec2Instance"]}'boto3 / call_boto3 Syntax
Parameter values and inner key names are the same for CLI and boto3 (top-level parameter names differ — CLI uses kebab-case like --order-by, boto3 uses camelCase like orderBy):
# List recommendation summaries
# groupBy valid values: AccountId, Region, ActionType, ResourceType,
# RestartNeeded, RollbackPossible, ImplementationEffort
client.list_recommendation_summaries(groupBy='ResourceType')
# List recommendations sorted by savings
# orderBy.dimension: EstimatedMonthlySavings, EstimatedSavingsPercentage
# orderBy.order: Asc, Desc (case-sensitive — "DESC" will fail)
client.list_recommendations(
orderBy={'dimension': 'EstimatedMonthlySavings', 'order': 'Desc'},
maxResults=20
)
# Filter by resource type
client.list_recommendations(
filter={'resourceTypes': ['Ec2Instance']},
maxResults=20
)
# Get details for a specific recommendation
client.get_recommendation(recommendationId='<id>')Common mistakes agents make with COH:
- Using
RecommendationTypeas groupBy (not a valid value — useResourceTypeorActionType) - Using
CostReductionas orderBy dimension (not valid — useEstimatedMonthlySavings) - Using
DESC/ASCinstead ofDesc/Asc(case-sensitive) - Calling non-existent operations like
get_savings_summaryordescribe_recommendations
Recommendation Types
| Type | Source | What It Finds |
|---|---|---|
| Rightsizing | Compute Optimizer | Over/under-provisioned EC2, Lambda, EBS, ECS, RDS |
| Idle resources | Compute Optimizer | EC2, EBS, ELB, RDS with near-zero utilization |
| Savings Plans | Cost Explorer | SP purchase recommendations |
| Reserved Instances | Cost Explorer | RI purchase recommendations |
| Graviton migration | Compute Optimizer | x86 → arm64 opportunities |
| EBS optimization | Compute Optimizer | gp2→gp3, io1→io2 migrations |
Filtering and Action Types
Action types (valid values for filter.actionTypes): Rightsize, Stop, Upgrade, PurchaseSavingsPlans, PurchaseReservedInstances, MigrateToGraviton, Delete, ScaleIn
Implementation effort levels (valid values for filter.implementationEfforts): VeryLow, Low, Medium, High, VeryHigh
Resource types (valid values for filter.resourceTypes): Ec2Instance, Ec2AutoScalingGroup, EbsVolume, LambdaFunction, EcsService, RdsDbInstance, RdsDbInstanceStorage, ComputeSavingsPlans, Ec2InstanceSavingsPlans, SageMakerSavingsPlans, Ec2ReservedInstances, RdsReservedInstances, OpenSearchReservedInstances, RedshiftReservedNodes, ElastiCacheReservedNodes, MemoryDbReservedInstances, DynamoDbReservedCapacity, AuroraDbClusterStorage, NatGateway
Idle vs Overprovisioned — Do NOT Confuse
Idle resources = near-zero utilization, safe to stop/delete. Action types: Stop, Delete. Overprovisioned resources = actively used but larger than needed, should be rightsized. Action type: Rightsize.
When a user asks "what idle resources can I terminate?" — only include Stop and Delete action types. Do NOT include Rightsize recommendations — those resources are still in use.
Compute Optimizer Detailed Operations
For deeper per-resource analysis beyond COH summaries, use Compute Optimizer directly:
# Check enrollment first
client.get_enrollment_status()
# Per-resource-type operations (service: compute-optimizer)
client.get_ec2_instance_recommendations(instanceArns=[...], filters=[...])
client.get_auto_scaling_group_recommendations(autoScalingGroupArns=[...])
client.get_ebs_volume_recommendations(volumeArns=[...])
client.get_lambda_function_recommendations(functionArns=[...])
client.get_rds_database_recommendations(resourceArns=[...])
client.get_ecs_service_recommendations(serviceArns=[...])
# Filters accept finding types: Underprovisioned, Overprovisioned, Optimized, NotOptimized
# Recommendation preferences: cpuVendorArchitectures=['AWS_ARM64'] for Graviton, ['CURRENT'] for same archDe-duplication of Savings Estimates
COH de-duplicates savings across overlapping recommendation types. A single EC2 instance may have recommendations for rightsizing, Savings Plans, Reserved Instances, AND Graviton migration — but implementing one changes the savings from the others.
list_recommendation_summariesreturns per-groupestimatedMonthlySavingsthat are NOT de-duped — summing them will overcount.- The same response includes
estimatedTotalDedupedSavingsat the top level — this IS the de-duped total. Always use this field for total savings. list_recommendationsreturns per-recommendationestimatedMonthlySavingsthat are also NOT de-duped across recommendations for the same resource.
NEVER sum individual recommendation savings to get a total. Use estimatedTotalDedupedSavings from list_recommendation_summaries instead.
Workflow
1. Start with COH to get the prioritized, de-duplicated list of all savings opportunities 2. For deeper analysis on a specific recommendation, use the source service directly:
- EC2 rightsizing details →
references/ec2-rightsizing.md - SP purchase analysis →
references/savings-plans.md - Lambda memory optimization →
references/lambda-optimization.md
3. Calculate savings using a script (see references/deterministic-calculations.md) — NEVER sum savings estimates manually
Gotchas
- COH requires opt-in:
aws cost-optimization-hub update-enrollment-status --status Active - COH is available in us-east-1 only
- Recommendations refresh approximately every 24 hours
- Savings estimates use On-Demand pricing by default — may overstate savings if customer already has SPs/RIs
- COH does NOT include per-service optimizations (S3 lifecycle, CloudWatch log retention, NAT Gateway endpoints) — see
references/service-optimization.mdfor those
CUR and AWS Data Exports
Which Report Format?
AWS has three billing data formats. Determine which the customer is using before writing queries:
| Format | Table Name | Status | Key Differences |
|---|---|---|---|
| CUR 2.0 | COST_AND_USAGE_REPORT | Recommended | Fixed schema, nested columns (resource_tags, cost_category, product, discount are key-value maps), Parquet/GZIP only. Created via AWS Data Exports. |
| Legacy CUR | User-defined | Still supported, no deprecation planned | Dynamic schema (columns vary monthly based on usage), tags/categories as separate columns (e.g., resource_tags_user_creator), supports CSV/ZIP/GZIP/Parquet. Created via CUR console or API. |
| FOCUS 1.2 | FOCUS_1_2_AWS | GA | FinOps Open Cost and Usage Specification — cloud-agnostic schema for multi-cloud FinOps. Different column names entirely (e.g., BilledCost, EffectiveCost, ServiceName). Created via AWS Data Exports. |
How to tell which format a customer has: Ask, or check the Data Exports console. If they reference billing_period as a string column, they're likely on Legacy CUR. If they reference bill_billing_period_start_date as a timestamp, they're on CUR 2.0.
Key query differences between Legacy CUR and CUR 2.0:
- Billing period filter: Legacy CUR uses
billing_period = '2026-03'(string). CUR 2.0 usesbill_billing_period_start_date = TIMESTAMP '2026-03-01'(timestamp). - Tags: Legacy CUR CSV has
resource_tags_user_<tagname>as separate columns. CUR 2.0 nests all tags into aresource_tagsmap column — query withresource_tags['user:tagname']. - Product attributes: Legacy CUR has
product_<attribute>as separate columns. CUR 2.0 nests intoproductmap — query withproduct['attribute']. - Table name: Legacy CUR uses whatever name the customer chose. CUR 2.0 is always
COST_AND_USAGE_REPORT.
Setup (CUR 2.0)
aws bcm-data-exports create-export --export '{
"Name":"MyCUR2Export",
"DataQuery":{"QueryStatement":"SELECT * FROM COST_AND_USAGE_REPORT",
"TableConfigurations":{"COST_AND_USAGE_REPORT":{"TIME_GRANULARITY":"DAILY","INCLUDE_RESOURCES":"TRUE"}}},
"DestinationConfigurations":{"S3Destination":{"S3Bucket":"my-cur-bucket","S3Prefix":"cur2","S3Region":"us-east-1",
"S3OutputConfigurations":{"OutputType":"CUSTOM","Format":"PARQUET","Compression":"PARQUET","Overwrite":"OVERWRITE_REPORT"}}},
"RefreshCadence":{"Frequency":"SYNCHRONOUS"}}'Always use PARQUET — 10-100x cheaper Athena queries than CSV. Set INCLUDE_RESOURCES=TRUE only if per-resource analysis needed (dramatically increases data volume).
Key Column Groups
| Group | Key Columns | Use |
|---|---|---|
| line_item | unblended_cost, resource_id, product_code, usage_amount | Core cost data |
| savings_plan | savings_plan_effective_cost, savings_plan_a_r_n | SP analysis |
| reservation | reservation_a_r_n, effective_cost, unused_quantity | RI analysis |
| pricing | public_on_demand_cost, public_on_demand_rate | On-demand comparison |
| resource_tags | Legacy CUR: resource_tags_user_<tagname> columns; CUR 2.0: resource_tags map — query with resource_tags['user:tagname'] | Tag-based allocation |
Common Athena Queries
CUR 2.0 uses bill_billing_period_start_date as a TIMESTAMP column, not a string. Filter with TIMESTAMP literal or date_trunc:
-- Monthly cost by service
SELECT line_item_product_code AS service, SUM(line_item_unblended_cost) AS cost
FROM cost_and_usage_report
WHERE bill_billing_period_start_date = TIMESTAMP '2026-03-01'
GROUP BY line_item_product_code ORDER BY cost DESC;
-- Top 10 most expensive resources
SELECT line_item_resource_id, line_item_product_code, SUM(line_item_unblended_cost) AS cost
FROM cost_and_usage_report
WHERE bill_billing_period_start_date = TIMESTAMP '2026-03-01' AND line_item_resource_id != ''
GROUP BY line_item_resource_id, line_item_product_code ORDER BY cost DESC LIMIT 10;
-- Data transfer breakdown (uses same regex patterns as cost-explorer.md)
SELECT line_item_product_code, line_item_usage_type,
SUM(line_item_usage_amount) AS usage_gb, SUM(line_item_unblended_cost) AS cost
FROM cost_and_usage_report
WHERE bill_billing_period_start_date = TIMESTAMP '2026-03-01'
AND (
REGEXP_LIKE(line_item_usage_type,
'DataTransfer|AWS-(In|Out)-Bytes|Bytes-(Internet|AWS)|CloudFront-.*-Bytes|DataXfer|-ABytes-')
OR REGEXP_LIKE(line_item_usage_type,
'NatGateway-Bytes|VpcEndpoint-Bytes|TransitGateway-Bytes')
OR (line_item_usage_type LIKE '%DataProcessing-Bytes%'
AND line_item_product_code = 'AWSELB')
)
GROUP BY line_item_product_code, line_item_usage_type ORDER BY cost DESC;
-- SP effective rate vs on-demand
SELECT line_item_product_code,
SUM(savings_plan_savings_plan_effective_cost) AS sp_cost,
SUM(pricing_public_on_demand_cost) AS ondemand_cost,
ROUND(1 - SUM(savings_plan_savings_plan_effective_cost) / NULLIF(SUM(pricing_public_on_demand_cost), 0), 3) AS savings_pct
FROM cost_and_usage_report
WHERE savings_plan_savings_plan_a_r_n IS NOT NULL
AND bill_billing_period_start_date = TIMESTAMP '2026-03-01'
GROUP BY line_item_product_code;Gotchas
- Confirm the report format first. Legacy CUR and CUR 2.0 have different column names, filtering syntax, and table names. Queries written for one will fail on the other.
- Service names differ between Cost Explorer and CUR. Cost Explorer uses human-readable names (e.g.,
Elastic Load Balancing). CUR uses API-style product codes (e.g.,AWSELB). Before writing filter queries, runSELECT DISTINCT line_item_product_codeto discover available values. If a filtered query returns 0 results, check the product code first. - CUR 2.0 table name is
COST_AND_USAGE_REPORT(fixed) — not user-defined - Tags differ by format: Legacy CUR uses
resource_tags_user_<tagname>columns. CUR 2.0 usesresource_tags['user:tagname']map syntax. Neither matches Cost Explorer API, which uses the tag key directly. - CUR data delivered to S3 up to 3 times daily — not real-time
- Current month CUR is incomplete until month closes — don't compare to Cost Explorer
- Tags activated after CUR creation require manual Athena table column addition
Additional Resources
- CUR Query Library (Well-Architected Labs): https://wellarchitectedlabs.com/cost-optimization/cur_queries/ — curated SQL queries for common cost analysis tasks (data transfer, EC2, RDS, S3, Savings Plans, etc.). NOTE: These queries are written for Legacy CUR column names — adapt for CUR 2.0 if needed (see "Key query differences" above).
- Data Transfer Cost Analysis Dashboard (Well-Architected Labs): https://wellarchitectedlabs.com/cost/200_labs/200_enterprise_dashboards/3_create_data_transfer_cost_analysis_dashboard/ — pre-built QuickSight dashboard for data transfer analysis from CUR data.
- CUR 2.0 column reference: https://docs.aws.amazon.com/cur/latest/userguide/table-dictionary-cur2.html
- FOCUS 1.2 column reference: https://docs.aws.amazon.com/cur/latest/userguide/table-dictionary-focus-1-2-aws.html
Deterministic Calculations
You MUST NEVER perform arithmetic by reasoning in your response. This includes sums, averages, percentages, percent changes, counts, min/max, or any math on data from API calls. LLM arithmetic is unreliable and produces wrong cost figures.
You MUST ALWAYS write a script to perform calculations and print the result.
Pattern: Python script for Cost Explorer data
After calling aws ce get-cost-and-usage, extract the numbers and calculate with a script:
# Example: Calculate total cost and percent change from CE response data
import json
# Data extracted from API responses (replace with actual values)
current_month = [("EC2", 1500.42), ("S3", 823.17), ("RDS", 612.90)]
previous_month = [("EC2", 1200.00), ("S3", 750.00), ("RDS", 580.00)]
current_total = sum(cost for _, cost in current_month)
previous_total = sum(cost for _, cost in previous_month)
pct_change = ((current_total - previous_total) / previous_total) * 100
print(f"Current total: ${current_total:,.2f}")
print(f"Previous total: ${previous_total:,.2f}")
print(f"Change: {pct_change:+.1f}%")
for service, cost in current_month:
pct_of_total = (cost / current_total) * 100
print(f" {service}: ${cost:,.2f} ({pct_of_total:.1f}%)")Pattern: Count and aggregate
# Example: Count exceeded budgets from Budgets API response
budgets = [("Monthly-Total", "EXCEEDED"), ("Dev-Budget", "OK"), ("Prod-Budget", "EXCEEDED")]
exceeded = [name for name, status in budgets if status == "EXCEEDED"]
print(f"Exceeded budgets: {len(exceeded)} — {', '.join(exceeded)}")Pattern: Savings calculation
# Example: Calculate savings from right-sizing recommendations
recs = [
{"instance": "i-abc123", "current_cost": 121.03, "recommended_cost": 16.64},
{"instance": "i-def456", "current_cost": 350.00, "recommended_cost": 175.00},
]
total_current = sum(r["current_cost"] for r in recs)
total_recommended = sum(r["recommended_cost"] for r in recs)
total_savings = total_current - total_recommended
pct_savings = (total_savings / total_current) * 100
print(f"Total monthly savings: ${total_savings:,.2f} ({pct_savings:.1f}%)")
print(f"Annual savings: ${total_savings * 12:,.2f}")Why this matters
- LLMs frequently make arithmetic errors on multi-digit numbers, especially with percentages and aggregations
- Cost data involves currency — wrong numbers erode customer trust immediately
- Scripts produce verifiable, reproducible results
- The AWS MCP server's
run_scripttool runs Python in a sandbox — use it when available
EBS Volume Optimization
Pricing note: All prices shown are us-east-1 approximate as of early 2026. Prices vary by region and may change. Always verify current pricing via the Price List API before reporting to users.
Volume Type Comparison
gp2 vs gp3
- gp2: IOPS tied to volume size (3 IOPS/GB). Uses burst buffer — can burst to 3,000 IOPS temporarily, then drops to baseline when credits depleted. A 100 GB gp2 volume has only 300 IOPS baseline.
- gp3: ~20% lower per-GB cost ($0.08 vs $0.10 in us-east-1; verify regional prices via Price List API). Consistent 3,000 IOPS + 125 MB/s baseline included for ANY volume size. No burst buffer. IOPS and throughput provisioned independently.
gp2 → gp3 migration is almost always a win: lower cost, consistent performance, no burst buffer management.
io1 vs io2
Same price ($0.125/GB + $0.065/PIOPS in us-east-1). io2 offers: higher durability (99.999% vs 99.8%), max IOPS up to 64K (or 256K with Block Express on Nitro instances) vs 64K for io1, Multi-Attach. Always prefer io2 over io1.
Compute Optimizer for EBS
Prerequisites: supported type (gp2/gp3/io1/io2), attached and in-use for full lookback, ≥24h CloudWatch metrics, no modification in past 24h.
Metrics: Read/Write IOPS (Max + Avg), Read/Write Bytes/sec (Max + Avg). 5-minute samples.
Findings: NotOptimized (can improve), Optimized (may still recommend type migration for cost/durability).
aws compute-optimizer get-ebs-volume-recommendations \
--filters Name=Finding,Values=NotOptimizedRoot Volume Considerations
- Root volumes contain the OS — modifications require extra caution
- Many modern instance types support Elastic Volumes for online modification
- Some older types may require scheduled restart
- Always verify instance type supports online modification before proceeding
Savings Formulas
io1/io2: Savings = (current_GB × $/GB + current_PIOPS × $/PIOPS) − (recommended_GB × $/GB + recommended_PIOPS × $/PIOPS)
gp2→gp3: Savings = (current_GB × gp2_$/GB) − (current_GB × gp3_$/GB + max(0, needed_IOPS − 3000) × gp3_$/IOPS + max(0, needed_throughput_MBps − 125) × gp3_$/throughput_MBps)
Look up regional prices via Price List API (see references/pricing-lookup.md). Prices vary significantly by region. needed_IOPS and needed_throughput_MBps: use Compute Optimizer recommended values when available, otherwise observed P99 from CloudWatch.
Gotchas
- gp2 burst buffer depletion causes sudden performance drops — common cause of unexplained latency
- Volume modifications are online (no detach needed) but take time to complete
- Storage can only be increased, not decreased
- After modification, must wait 6 hours before another modification
EC2 Right-Sizing with Compute Optimizer
Prerequisites
Opt in first: aws compute-optimizer update-enrollment-status --status Active
Metrics Analyzed
Performance: CPU utilization, memory utilization (requires CloudWatch agent), GPU utilization/memory (requires CloudWatch agent + NVIDIA GPU)
Network: NetworkIn/Out bytes/sec, packets in/out per second
EBS: Read/Write bytes/sec, Read/Write ops/sec
Instance Store: Disk read/write bytes/sec, disk read/write ops/sec
Memory metrics are critical — without them, instances with low memory may appear optimized. Memory metrics enable up to 4x more savings opportunities. Recommend CloudWatch agent installation.
Finding Classifications
| Finding | Meaning |
|---|---|
Overprovisioned | Can be downsized while meeting workload needs |
Underprovisioned | Too small, risking performance issues |
Optimized | Appropriately sized |
NotOptimized | Could benefit from newer generation or family |
Finding Reason Codes
Each finding includes reason codes explaining which metrics triggered it: CPUOverprovisioned, CPUUnderprovisioned, MemoryOverprovisioned, MemoryUnderprovisioned, EBSThroughputOverprovisioned, NetworkBandwidthOverprovisioned, GPUOverprovisioned, etc. Found in findingReasonCodes array.
Lookback Periods
| Period | Datapoints | Cost |
|---|---|---|
| 14-day (default) | ~4,032 | Free |
| 32-day | ~9,216 | Free (enhanced) |
| 93-day | ~26,784 | Paid (enhanced infrastructure metrics) |
Uses P99.5 percentile by default (excludes top 0.5% outliers). Default 20% CPU/memory headroom buffer.
Migration Effort Levels
| Level | Example |
|---|---|
| Very Low | Same family size change (c5.large → c5.xlarge) |
| Low | Generation change (m5.xlarge → m6i.xlarge) |
| Medium | Family change (c5.xlarge → m5.xlarge) |
| High | Architecture change (x86 → Graviton/arm64) |
Performance Risk Scale
0-1: Very Low | >1-2: Low | >2-3: Medium | >3-4: High
Savings Estimation Modes
Check effectiveRecommendationPreferences.savingsEstimationMode.source:
PublicPricing: On-Demand pricing (default)CostExplorerRightsizing: Incorporates SP/RI discountsCostOptimizationHub: Custom pricing
If only savingsOpportunity is present, calculation uses On-Demand. If savingsOpportunityAfterDiscounts is also present, compare both.
CLI Commands
# Over-provisioned EC2 instances
aws compute-optimizer get-ec2-instance-recommendations \
--filters Name=Finding,Values=Overprovisioned
# Idle resources (near-zero utilization)
aws compute-optimizer get-idle-recommendations
# Export to S3 for bulk analysis
aws compute-optimizer export-ec2-instance-recommendations \
--s3-destination-config bucket=my-bucket,keyPrefix=ec2-recs \
--file-format CsvAnalyzing a Recommendation
When presenting a right-sizing recommendation to the user, include:
1. Current instance type and specs (vCPUs, memory) 2. Which metrics triggered the finding (with actual values) 3. Recommended instance type and specs 4. Monthly savings ($ and %) — calculate with a script, NEVER manually 5. Migration effort level and any platform differences (Xen→Nitro, x86→arm64) 6. Whether memory metrics were available (if not, recommend CloudWatch agent)
Free Tier
July 2025 Transition
AWS transitioned from time-based to credit-based free tier on July 15, 2025:
| Account Type | Model | Details |
|---|---|---|
| Legacy (before July 15, 2025) | 12-month free tier + Always Free | Original offers, complete naturally. Always Free services available. |
| Free Plan (after July 15, 2025) | $200 credits for 6 months | No charges during free period. Upgrade to Paid Plan after. Always Free services available. |
| Paid Plan (after July 15, 2025) | $200 credits for 6 months | Charged for usage exceeding credits. Always Free services available. |
~30 Always Free services remain available indefinitely for all account types.
Recommended Workflow
1. First: aws freetier get-account-plan-state — determine account type and eligibility 2. Then: aws freetier get-free-tier-usage — check current usage for active services
Critical Rules
- NEVER cite specific free tier limits from training data — offers changed July 15, 2025 and vary by account type
getFreeTierUsageonly returns services with usage > 0. Missing service means either no free tier offer exists OR customer hasn't used it yet.- For questions about available offers before using a service, direct to https://aws.amazon.com/free/
- Legacy accounts: former 12-month services stop appearing after their period expires
- Free Plan/Paid Plan: $200 credit replaced 12-month offers. Always Free services tracked individually.
# Check account plan state
aws freetier get-account-plan-state
# Check current free tier usage
aws freetier get-free-tier-usageLambda Optimization
Pricing note: All prices shown are us-east-1 approximate as of early 2026. Prices vary by region and may change. Always verify current pricing via the Price List API before reporting to users.
Memory-CPU Relationship
Lambda allocates CPU proportional to memory:
- 1,769 MB = 1 full vCPU
- 10,240 MB = 6 vCPUs
Over-provisioning memory gives more CPU, which can reduce duration enough to lower total cost. Cost = Invocations × Duration(ms) × Memory(GB) × Price/GB-ms + Request charges.
Compute Optimizer for Lambda
Requirements: ≤1,792 MB memory AND ≥50 invocations in the lookback period.
Metrics analyzed: Invocations, Duration, Errors, Throttles, Memory Utilization. The engine simulates candidate memory sizes, projects duration, and selects the size that finishes within timeout and produces greatest monthly savings.
Findings: NotOptimized (can be improved), Optimized, Unavailable (insufficient data). Note: Lambda and EC2 use different finding value sets. Lambda: NotOptimized/Optimized/Unavailable. EC2: Overprovisioned/Underprovisioned/Optimized/NotOptimized.
aws compute-optimizer get-lambda-function-recommendations \
--filters Name=Finding,Values=NotOptimizedOptimization Levers
| Strategy | Savings | Effort |
|---|---|---|
| Switch to arm64 (Graviton) | ~20% cost + ~10-15% faster | Low — config change |
| Right-size memory with Power Tuning | 10-50% | Medium |
| Use SnapStart (Java/Python/.NET) | Eliminates provisioned concurrency cost | Low |
# Switch to arm64
aws lambda update-function-configuration \
--function-name my-function --architectures arm64Gotchas
- arm64 not available in all regions; native compiled dependencies need arm64 builds
- Reserved concurrency (free) ≠ Provisioned concurrency (paid) — most common Lambda cost confusion
- Provisioned concurrency costs ~$0.015/GB-hour even when idle — use SnapStart instead where possible
- Lambda needs 14 days of CloudWatch metrics before Compute Optimizer generates recommendations
- Use
alexcasalboni/aws-lambda-power-tuningStep Functions state machine for systematic memory optimization
AWS Pricing Lookup
Price List API service codes differ from Cost Explorer service names. Use these exact codes.
Common Service Codes
| Service | Price List Code | Cost Explorer Name |
|---|---|---|
| EC2 | AmazonEC2 | Amazon Elastic Compute Cloud - Compute |
| Lambda | AWSLambda | AWS Lambda |
| S3 | AmazonS3 | Amazon Simple Storage Service |
| RDS | AmazonRDS | Amazon Relational Database Service |
| DynamoDB | AmazonDynamoDB | Amazon DynamoDB |
| ElastiCache | AmazonElastiCache | Amazon ElastiCache |
| Redshift | AmazonRedshift | Amazon Redshift |
| ECS | AmazonECS | Amazon Elastic Container Service |
| CloudFront | AmazonCloudFront | Amazon CloudFront |
| Bedrock | AmazonBedrock | Amazon Bedrock |
EC2 Pricing Attributes
- Filter instances:
productFamily: "Compute Instance" - Reserved Instances:
termType: "Reserved", checkLeaseContractLength,OfferingClass,PurchaseOption - Spot and Capacity Block pricing are NOT in the Price List API
S3 Pricing Attributes
Filter storage: productFamily: "Storage". Use volumeType (NOT storageClass):
| Storage Class | volumeType Value |
|---|---|
| Standard | "Standard" |
| Infrequent Access | "Standard - Infrequent Access" |
| One Zone IA | "One Zone - Infrequent Access" |
| Glacier Instant Retrieval | "Glacier Instant Retrieval" |
| Glacier Flexible | "Amazon Glacier" |
| Glacier Deep Archive | "Glacier Deep Archive" |
| Intelligent-Tiering | "Intelligent-Tiering" |
Intelligent-Tiering has 5 sub-tiers with distinct volumeType values: "Intelligent-Tiering Frequent Access", "Intelligent-Tiering Infrequent Access", "Intelligent-Tiering Archive Instant Access", "IntelligentTieringArchiveAccess", "IntelligentTieringDeepArchiveAccess". For complete IT cost analysis, also query monitoring fee (feeCode: "S3-Monitoring and Automation-ObjectCount") and transition costs (operation: "S3-INTTransition").
API requests: productFamily: "API Request", check group for request type (PUT, GET).
RDS Pricing Attributes
databaseEngine:"MySQL","PostgreSQL","MariaDB","Aurora MySQL","Aurora PostgreSQL","SQL Server","Oracle","Db2"deploymentOption:"Single-AZ","Multi-AZ","Multi-AZ (readable standbys)"databaseEdition: for Oracle/SQL Server —"Standard","Enterprise","Express","Web"licenseModel: important for Oracle and SQL Server- Instances:
productFamily: "Database Instance". Storage:"Database Storage". Aurora Serverless:"Serverless"or"ServerlessV2"
General Rules
- Price List API is only available in `us-east-1` and `ap-south-1` — always specify
--region us-east-1 - AWS uses binary system: 1 KB = 1,024 bytes
- Monthly calculations: use 730 hours/month
- Volume-based pricing: check
beginRangeandendRangeinpriceDimensions - Pricing is public on-demand only — does not reflect customer-specific discounts
- Always refer customers to the AWS Pricing Calculator for detailed estimates
# List available service codes
aws pricing describe-services --region us-east-1
# Get attribute values for a service
aws pricing get-attribute-values \
--service-code AmazonEC2 --attribute-name instanceType --region us-east-1
# Get pricing for specific product
aws pricing get-products \
--service-code AmazonEC2 --region us-east-1 \
--filters Type=TERM_MATCH,Field=instanceType,Value=m5.xlarge \
Type=TERM_MATCH,Field=location,Value="US East (N. Virginia)" \
Type=TERM_MATCH,Field=operatingSystem,Value=Linux \
Type=TERM_MATCH,Field=tenancy,Value=Shared \
Type=TERM_MATCH,Field=preInstalledSw,Value=NA \
Type=TERM_MATCH,Field=capacitystatus,Value=UsedRDS Optimization
Compute Optimizer for RDS
Supported engines: MySQL, PostgreSQL, Aurora MySQL, Aurora PostgreSQL.
Metrics analyzed: CPUUtilization, DatabaseConnections, NetworkReceive/TransmitThroughput, ReadIOPS/WriteIOPS, ReadThroughput/WriteThroughput, EBSIOBalance%/EBSByteBalance%, FreeStorageSpace. With Performance Insights: DBLoad, os.swap.in/out.
Finding classifications: Overprovisioned, Underprovisioned, Optimized.
Finding reason codes: CPUOverprovisioned, CPUUnderprovisioned, MemoryUnderprovisioned (high swap/OOM), NetworkBandwidthOver/Under, EBSThroughput/IOPSOver/Under, NewGenerationAvailable, NewEngineVersionAvailable.
Storage findings: EBSVolumeAllocatedStorageUnderprovisioned, EBSVolumeIOPS/ThroughputOver/Under, NewGenerationStorageTypeAvailable.
aws compute-optimizer get-rds-db-instance-recommendations \
--filters Name=Finding,Values=OverprovisionedMulti-AZ Considerations
- Changes apply to both primary and standby instances
- Failover timing may be affected by instance changes
- Multi-AZ reduces downtime during modifications
Read Replica Considerations
- Recommendations synchronized with writer for promotion tiers ≤1
- Smaller replica instances may increase replication lag
Storage Considerations
- Storage can only be increased, not decreased
- Storage type changes may require specific instance types
- gp3 provides more flexible IOPS/throughput provisioning than gp2
Gotchas
- DB instance modifications typically require brief downtime (5-10 min)
- Engine version upgrades require compatibility assessment
- Parameter group changes may be required after instance class change
- Always take a snapshot before implementing changes
- Performance risk scale: 0-1 Very Low, >1-2 Low, >2-3 Medium, >3-4 High
Reserved Instances
RI Types
| Type | Discount | Flexibility | Marketplace |
|---|---|---|---|
| Standard | Up to 72% | Size flexibility within family (regional) | Can sell |
| Convertible | Up to 66% | Can exchange for different family/size/OS | Cannot sell |
Payment Options
All Upfront (highest discount) > Partial Upfront > No Upfront (lowest discount).
Break-Even Points
- 1-year RI: typically 7-10 months
- 3-year RI: typically 10-14 months
Size Flexibility (Regional RIs)
Regional RIs (both Standard and Convertible) automatically apply across instance sizes within the same family using normalization factors. Example: 1 c5.xlarge RI covers 2 c5.large instances. AZ-scoped RIs provide capacity reservation but NO size flexibility.
Application Order
RIs apply first, then Savings Plans cover remaining eligible usage.
Service-Specific Considerations
EC2: Available for Linux, RHEL, SUSE, Windows. Regional or zonal. Size flexibility within family (except dedicated tenancy).
RDS: Available for MySQL, PostgreSQL, MariaDB, Oracle, SQL Server, Aurora. Size flexibility within family. Automatically applied to Multi-AZ deployments.
ElastiCache: Redis/Valkey and Memcached. Redis/Valkey reserved nodes support size flexibility within family. Memcached reserved nodes do not.
OpenSearch: Specific instance types in specific regions. No size flexibility. Cannot sell on Marketplace.
Redshift: Specific node types in specific regions.
CLI Commands
# RI utilization
aws ce get-reservation-utilization \
--time-period Start=2026-03-01,End=2026-04-01 \
--granularity MONTHLY
# RI purchase recommendations
aws ce get-reservation-purchase-recommendation \
--service "Amazon Elastic Compute Cloud - Compute" \
--term-in-years ONE_YEAR \
--payment-option NO_UPFRONT \
--lookback-period-in-days SIXTY_DAYS
# RI coverage
aws ce get-reservation-coverage \
--time-period Start=2026-03-01,End=2026-04-01 \
--granularity MONTHLYGotchas
- Standard RIs can be sold on Marketplace; Convertible cannot
- Regional RIs provide size flexibility; AZ-scoped provide capacity reservation — pick one
- DynamoDB Reserved Capacity is deprecated — use Database Savings Plans instead
- RI modifications (splitting/merging) don't change the term or payment — only the instance count and AZ
Savings Plans
Pricing note: All prices shown are approximate as of early 2026 and may change. Always verify current pricing via the Price List API before reporting to users.
Plan Types
| Type | Discount | Flexibility | Covers |
|---|---|---|---|
| Compute SP | Up to 66% | Any family, size, region, OS | EC2, Fargate, Lambda |
| EC2 Instance SP | Up to 72% | Any size, OS within family+region | EC2 only |
| Database SP | Up to 35% | Any engine, family, size, region | Aurora, RDS, DynamoDB, ElastiCache, DocumentDB, Neptune, Keyspaces, Timestream, DMS, OpenSearch |
| SageMaker SP | Up to 64% | Any family, size, region | SageMaker |
Default recommendation: Compute SP for most users. The 6% discount gap vs EC2 Instance SP is not worth the inflexibility.
Default payment: No Upfront for first-time buyers to minimize risk.
How Recommendations Are Calculated
The recommendation engine analyzes usage over a lookback period (7, 30, or 60 days), considering every usage hour including nights and weekends. It selects a commitment ($/hr) that maximizes savings while maintaining high utilization.
Utilization = committed dollars used ÷ committed dollars purchased. Target >95%.
Savings = On-Demand cost − (SP cost + remaining On-Demand cost).
Savings compare to On-Demand prices only. The estimatedMonthlyCost and estimatedMonthlySavings in Cost Optimization Hub are monthly figures. The EstimatedOnDemandCostWithCurrentCommitment in additional details covers the lookback period — do NOT conflate lookback-period costs with monthly costs.
SP vs Reserved Instances
| Feature | Savings Plans | Reserved Instances |
|---|---|---|
| Flexibility | High (Compute SP covers EC2+Fargate+Lambda) | Low (service-specific) |
| Capacity reservation | No | Yes (AZ-scoped RI — Standard or Convertible) |
| Marketplace resale | No | Yes (Standard RI only) |
| AWS recommendation | Preferred | Legacy, still supported |
SPs apply AFTER RI discounts. SPs do NOT apply to Spot usage.
Use RIs only when: capacity reservation needed in specific AZ, want to sell on Marketplace, or very stable single-instance-type workload.
Gotchas
- 7-day return window (conditional): SPs with hourly commitment ≤$100, purchased in the past 7 days AND in the same calendar month, can be returned for a full refund. Usage covered by the returned plan is re-rated to On-Demand. Outside this window, commitment is binding for the full term.
- Compute SP does NOT cover RDS — use Database SP
- SP doesn't provide capacity reservation — use ODCR separately
- EKS control plane ($0.10/hr) is NOT covered by any SP
- DynamoDB Reserved Capacity is deprecated in favor of Database SP
- Start with Cost Explorer recommendations — they analyze actual usage patterns
CLI Commands
# Get SP purchase recommendation
aws ce get-savings-plans-purchase-recommendation \
--savings-plans-type COMPUTE_SP \
--term-in-years ONE_YEAR \
--payment-option NO_UPFRONT \
--lookback-period-in-days SIXTY_DAYS
# Check utilization
aws ce get-savings-plans-utilization \
--time-period Start=2026-03-01,End=2026-04-01 \
--granularity MONTHLY
# Check coverage
aws ce get-savings-plans-coverage \
--time-period Start=2026-03-01,End=2026-04-01 \
--granularity MONTHLYPer-Service Cost Optimization
Pricing note: All prices shown are us-east-1 approximate as of early 2026. Prices vary by region and may change. Always verify current pricing via the Price List API before reporting to users.
Quick wins that don't require commitment purchases. Prioritize by estimated savings.
S3: Storage Class Optimization
| Strategy | Savings | When |
|---|---|---|
| Intelligent-Tiering | Auto-optimized | Unknown access patterns, objects ≥128KB |
| Lifecycle to S3-IA | ~45% storage | Known infrequent access after 30+ days |
| Lifecycle to Glacier IR | ~68% storage | Archive after 90+ days, retrieval in minutes |
| Lifecycle to Deep Archive | ~95% storage | Compliance retention, 12+ hour retrieval OK |
Gotchas: Objects <128KB NOT auto-tiered in IT. Minimum storage durations: S3-IA 30 days, Glacier IR 90 days, Deep Archive 180 days — early deletion incurs prorated charge. Always add NoncurrentVersionExpiration — old versions accumulate silently.
Lambda: Memory and Architecture
| Strategy | Savings | Effort |
|---|---|---|
| Switch to arm64 (Graviton) | ~20% cost | Low — config change |
| Right-size memory | 10-50% | Medium — use Power Tuning |
| SnapStart (Java/Python/.NET) | Eliminates provisioned concurrency cost | Low |
Gotchas: Reserved concurrency (free) ≠ Provisioned concurrency (paid). 1,769 MB = 1 full vCPU — more memory = more CPU = potentially lower total cost.
NAT Gateway: VPC Endpoints
NAT Gateway: ~$0.045/hr (~$32/month) + ~$0.045/GB. Often the #1 surprise cost.
Always create free gateway endpoints for S3 and DynamoDB:
aws ec2 create-vpc-endpoint --vpc-id vpc-123abc \
--service-name com.amazonaws.<REGION>.s3 --route-table-ids rtb-123abcInterface endpoints cost ~$0.01/hr/AZ + ~$0.01/GB — cheaper than NAT only for high-traffic services. Do the math before adding many interface endpoints.
CloudWatch: Log Retention
Default retention is "Never expire" — logs accumulate at ~$0.03/GB/month.
# Find log groups without retention
aws logs describe-log-groups \
--query "logGroups[?!retentionInDays].{Name:logGroupName,StoredBytes:storedBytes}" --output tableGotchas: Log class cannot be changed after creation. Infrequent Access class does NOT support metric filters, subscription filters, or live tail. Custom metrics: each unique dimension combination is a separate metric (~$0.30/metric/month in us-east-1).
DynamoDB: Capacity Mode
On-demand is ~6x more expensive per request than provisioned at steady state. Start on-demand for new tables, switch to provisioned once traffic patterns are known. Can switch modes once per 24 hours. Database Savings Plans (up to 35%) now apply to DynamoDB on-demand.
ECS/EKS: Fargate Spot
Fargate Spot: up to 70% discount, 2-minute interruption warning. Always have Fargate fallback with base=1. EKS control plane costs $0.10/hr ($73/month) regardless of node count — not covered by any SP.
Related skills
How it compares
Use aws-billing-and-cost-management for agent-native AWS FinOps tasks instead of generic cloud skills that lack CUR, Compute Optimizer, and billing view scoping.
FAQ
Why check the current date first?
Models often use stale training years; wrong periods produce plausible but incorrect analyses.
Can I sum costs in the response text?
No. Always use a script for sums, averages, and percentages on API results.
How scope to a billing view?
List views with aws billing list-billing-views then pass --billing-view-arn on supported CE calls.
Is Aws Billing And Cost Management safe to install?
skills.sh reports 2 of 3 security scanners passed. Review the Security Audits panel on this page before installing in production.