How I Cut My AWS Bill by 60% Without Changing Code
How I Cut My AWS Bill by 60% Without Changing Code
Our AWS bill hit $12,000 last month. For a startup with 50,000 users, that was unsustainable. Three weeks later, we cut it to $4,800—without changing a single line of application code.
Here's exactly what we did.
The Wake-Up Call
I got the bill notification at 9 PM. $12,347.82. My heart sank. We were burning through our runway on cloud costs.
The worst part? Our traffic hadn't increased. We were just... inefficient.
Step 1: Actually Look at the Bill
This sounds obvious, but we'd been ignoring the details. AWS bills are intimidating. Hundreds of line items. Cryptic service names. It's easier to just pay it.
But when I finally dug in, patterns emerged:
- EC2: $4,200 (35%)
- RDS: $3,100 (26%)
- Data Transfer: $2,400 (20%)
- EBS: $1,200 (10%)
- Everything else: $1,447 (9%)
Now I had targets.
Step 2: Right-Size EC2 Instances
We were running m5.2xlarge instances (8 vCPUs, 32GB RAM) because... honestly, I don't remember why. Probably copied from a tutorial.
I checked actual usage with CloudWatch:
- Average CPU: 15%
- Average Memory: 40%
We were massively over-provisioned.
The Fix:
- Switched to m5.large (2 vCPUs, 8GB RAM)
- Added auto-scaling to handle traffic spikes
- Enabled AWS Compute Optimizer recommendations
Savings: $2,100/month
Step 3: Use Reserved Instances
We were paying on-demand prices for instances that ran 24/7. Reserved Instances offer up to 72% discount for 1-year commitments.
The Fix:
- Bought 1-year Reserved Instances for baseline capacity
- Kept auto-scaling on-demand for spikes
Savings: $800/month
Step 4: Optimize RDS
Our PostgreSQL database was a db.r5.2xlarge. Again, way oversized.
Actual usage:
- CPU: 20%
- Memory: 50%
- IOPS: 30% of provisioned
The Fix:
- Downgraded to db.r5.large
- Switched from Provisioned IOPS to GP3 storage
- Enabled automated backups to S3 (cheaper than RDS snapshots)
Savings: $1,400/month
Step 5: Attack Data Transfer Costs
Data transfer was killing us. $2,400/month for moving data around.
The culprit? We were serving images directly from S3 in a different region than our EC2 instances.
The Fix:
- Moved S3 bucket to same region as EC2 (free transfer)
- Added CloudFront CDN (cheaper than cross-region transfer)
- Enabled S3 Transfer Acceleration for uploads
Savings: $1,600/month
Step 6: Clean Up EBS Volumes
We had 47 unattached EBS volumes. Orphaned from terminated instances. Each costing $0.10/GB/month.
Total waste: $470/month
The Fix:
# Find unattached volumes
aws ec2 describe-volumes \
--filters Name=status,Values=available \
--query 'Volumes[*].[VolumeId,Size]'
# Delete them
aws ec2 delete-volume --volume-id vol-xxxxx
Savings: $470/month
Step 7: Optimize S3 Storage
We had 2TB in S3. Most of it old logs and backups we never accessed.
The Fix:
- Moved logs older than 30 days to S3 Glacier ($0.004/GB vs $0.023/GB)
- Set up lifecycle policies to automate this
- Deleted truly unnecessary data
{
"Rules": [{
"Id": "MoveOldLogs",
"Status": "Enabled",
"Transitions": [{
"Days": 30,
"StorageClass": "GLACIER"
}]
}]
}
Savings: $280/month
Step 8: Use Spot Instances for Background Jobs
We run nightly data processing jobs. These don't need to be on-demand.
The Fix:
- Moved batch jobs to Spot Instances (up to 90% discount)
- Made jobs fault-tolerant (Spot can be interrupted)
Savings: $350/month
Step 9: Enable AWS Cost Anomaly Detection
AWS has a free service that alerts you to unusual spending. We enabled it and caught a misconfigured Lambda function that was running in a loop.
The Fix:
- Enabled Cost Anomaly Detection
- Set up SNS alerts for spending spikes
- Fixed the runaway Lambda
Savings: $200/month (from the Lambda bug)
Step 10: Consolidate Accounts
We had three AWS accounts (dev, staging, prod). Each had its own NAT Gateway ($32/month), load balancers, etc.
The Fix:
- Consolidated to one account with separate VPCs
- Shared NAT Gateways where possible
- Used tags for cost allocation
Savings: $180/month
The Results
Before: $12,348/month
After: $4,818/month
Savings: $7,530/month (61%)
That's $90,360 per year. For a startup, that's runway.
Tools That Helped
- AWS Cost Explorer: Visualize spending patterns
- AWS Trusted Advisor: Free recommendations
- CloudWatch: Monitor actual resource usage
- AWS Compute Optimizer: Right-sizing recommendations
- Infracost: Estimate costs before deploying
Ongoing Optimization
We now:
- Review AWS bill weekly
- Set budget alerts at $5,000
- Tag all resources for cost tracking
- Run monthly cost optimization reviews
What We Didn't Do
Notice we didn't:
- Rewrite the application
- Change databases
- Migrate to another cloud
- Compromise on performance
This was pure infrastructure optimization.
Lessons Learned
-
Default configurations are expensive: AWS defaults to high-availability, high-performance options. You're paying for features you might not need.
-
Monitor actual usage: Don't guess. Use CloudWatch to see real CPU, memory, and IOPS usage.
-
Reserved Instances are worth it: If you know you'll run something for a year, commit to it.
-
Data transfer adds up: Keep data in the same region. Use CloudFront for global distribution.
-
Clean up regularly: Unattached volumes, old snapshots, unused elastic IPs—they all cost money.
The Uncomfortable Truth
We were wasting $7,500/month because I was too busy to look at the bill. That's on me.
AWS makes it easy to spend money. They don't make it easy to save money. You have to be proactive.
Your Action Plan
- This week: Look at your AWS bill. Really look at it.
- This month: Right-size your EC2 and RDS instances
- This quarter: Implement Reserved Instances and Savings Plans
- Ongoing: Set up cost alerts and review monthly
You don't need to change your code. You just need to pay attention.
Our $7,500/month savings bought us six extra months of runway. That might be the difference between success and failure.