Cloud bills grow faster than teams expect. You start with a few EC2 instances, add RDS, some S3 buckets, a load balancer — and suddenly you're looking at a bill that's three times what you budgeted. Here are the strategies I use with clients to bring costs down significantly without breaking anything.
1. Right-Size Your EC2 Instances
The most common waste in AWS is over-provisioned instances. Teams launch m5.2xlarge because "it seemed safe" and never revisit it.
Use AWS Cost Explorer's right-sizing recommendations and check actual CPU/memory utilization over 14 days. A rule of thumb: if average CPU is below 20%, you can likely go one size down.
# Pull utilization stats via AWS CLI
aws cloudwatch get-metric-statistics \
--namespace AWS/EC2 \
--metric-name CPUUtilization \
--dimensions Name=InstanceId,Value=i-0abc123 \
--start-time 2026-08-01T00:00:00Z \
--end-time 2026-08-28T00:00:00Z \
--period 86400 \
--statistics Average
Don't right-size blindly. Check memory too — EC2 metrics don't include memory by default, so install the CloudWatch agent.
2. Reserved Instances and Savings Plans
On-demand pricing is the most expensive way to run steady workloads. For anything running 24/7, move to:
- 1-year Savings Plan — up to 40% discount, flexible across instance types
- 3-year Reserved Instances — up to 72% discount, for very stable workloads
- Convertible Reserved Instances — cheaper than on-demand, exchangeable
The key is coverage analysis. Use the Savings Plans coverage report in Cost Explorer. Aim for 80%+ of your compute covered by savings commitments.
Baseline workloads → Reserved Instances / Savings Plans
Variable workloads → On-Demand
Fault-tolerant jobs → Spot Instances (up to 90% cheaper)
3. Spot Instances for the Right Workloads
Spot Instances are EC2 capacity sold at up to 90% discount. They can be interrupted with 2 minutes' notice. That's fine for:
- CI/CD build agents
- Batch processing jobs
- ML training
- Stateless microservices with proper interruption handling
Use Spot with Auto Scaling groups and mixed instance policies:
# Auto Scaling Group mixed instances policy
MixedInstancesPolicy:
InstancesDistribution:
OnDemandBaseCapacity: 2 # Always 2 on-demand for baseline
OnDemandPercentageAboveBaseCapacity: 0 # Rest goes Spot
SpotAllocationStrategy: price-capacity-optimized
LaunchTemplate:
LaunchTemplateSpecification:
LaunchTemplateId: !Ref LaunchTemplate
Overrides:
- InstanceType: m5.large
- InstanceType: m5a.large
- InstanceType: m4.large
Multiple instance types in your Spot pool reduces interruption risk significantly.
4. Clean Up Unused Resources
Run this audit monthly. The savings are easy money:
Unattached EBS volumes — snapshots piling up, volumes detached after instance termination:
aws ec2 describe-volumes \
--filters Name=status,Values=available \
--query 'Volumes[*].{ID:VolumeId,Size:Size,Type:VolumeType}'
Unused Elastic IPs — $0.005/hour each when not attached. Not much individually, but they add up.
Idle load balancers — ALBs and NLBs with zero traffic cost ~$16/month minimum.
Old AMIs and snapshots — forgotten after replacing instances.
Oversized NAT Gateways — data processing charges are often the hidden cost here.
5. S3 Storage Classes
S3 Standard is expensive for data you rarely access. Use lifecycle policies:
{
"Rules": [{
"Status": "Enabled",
"Transitions": [
{ "Days": 30, "StorageClass": "STANDARD_IA" },
{ "Days": 90, "StorageClass": "GLACIER_IR" },
{ "Days": 365, "StorageClass": "DEEP_ARCHIVE" }
]
}]
}
S3 Intelligent-Tiering is worth considering for data with unpredictable access patterns — it moves objects automatically between tiers.
6. RDS Optimization
Use Aurora Serverless v2 for dev/staging databases that are idle most of the day — you only pay for ACUs when the DB is active.
Stop non-production RDS instances on a schedule. A dev database running 8 hours/day instead of 24 saves ~66% on instance costs.
# Stop RDS instance (automatically starts after 7 days per AWS policy)
aws rds stop-db-instance --db-instance-identifier myapp-dev
Read replicas — make sure they're actually being used. I've seen setups with 3 read replicas that all pointed to the same single app server.
7. Set Budgets and Alerts
You can't optimize what you don't monitor. Set up AWS Budgets:
- Monthly cost budget with alert at 80% and 100%
- Service-specific budgets for EC2, RDS, data transfer
- Anomaly detection for unexpected spending spikes
Cost optimization is an ongoing process, not a one-time task. Schedule a monthly 30-minute review of your Cost Explorer dashboard. The savings compound quickly.
