The 30% figure is not a best-case scenario. It is the floor. Every time I go through an account that has never been audited, I find it within a week, usually faster. No code changes, no architecture work. Just a structured look at what you are actually paying for.
The 30% figure is not a marketing number. The Flexera 2026 State of the Cloud report puts average waste at 27-32%. The LeanOps FinOps playbook documents 30% as consistently achievable on a first audit of accounts that have never been reviewed. I have done this across enough accounts to confirm that number is real. Let me walk you through the process.
Day 1: Get a clear picture of what you are paying for
Before you cut anything, understand the bill. Go to AWS Cost Explorer or Azure Cost Management and look at the last 3 months. Group costs by Service, then by Usage Type.
What you are looking for in this step:
- Which services are your top three costs?
- Is anything growing month over month without an obvious reason?
- Are there any services you do not recognize in the bill?
# Get your month-to-date costs broken down by service (AWS CLI)
aws ce get-cost-and-usage --time-period Start=2026-03-01,End=2026-03-31 --granularity MONTHLY --metrics "BlendedCost" --group-by Type=DIMENSION,Key=SERVICE --query 'ResultsByTime[0].Groups[*].[Keys[0],Metrics.BlendedCost.Amount]' --output table | sort -k2 -rnWrite down the top five line items and what percentage of your total bill each one represents. This is your map for the rest of the week.
Day 2: Delete what you are not using
This is the fastest savings. No architectural decisions. Just cleanup.
The checklist:
- Unattached Elastic IPs: Go to EC2 → Elastic IPs. Release anything with no association. Every unattached IP costs $3.60/month.
- Old snapshots: Go to EC2 → Snapshots. Sort by date. Delete anything older than your retention policy. Each GB costs $0.05-0.10/month.
- Unused load balancers: An ALB or NLB with no registered targets is billing you hourly. Delete it.
- Old Lambda versions: Lambda stores deployment packages. Old function versions accumulate and incur storage charges. Delete everything except the $LATEST alias.
- Unused ECR images: If you are pushing Docker images to ECR on every CI build, old layers accumulate. Set a lifecycle policy to keep only the last 10 images.
# Set ECR lifecycle policy to keep only 10 most recent images
aws ecr put-lifecycle-policy --repository-name your-repo-name --lifecycle-policy-text '{
"rules": [{
"rulePriority": 1,
"description": "Keep last 10 images",
"selection": {
"tagStatus": "any",
"countType": "imageCountMoreThan",
"countNumber": 10
},
"action": { "type": "expire" }
}]
}'Day 3: Rightsize the compute
Run AWS Compute Optimizer or check Azure Advisor. Both tools analyze your actual CPU and memory utilization from the last 14 days and recommend the smallest instance type that will handle your peak load.
An m5.xlarge (4 vCPU, 16GB RAM) costs about $0.192/hour. If Compute Optimizer says it is running at 5% CPU and 20% memory, you could run it on a t3.medium (2 vCPU, 4GB RAM) at $0.0416/hour. That is a 78% cost reduction on that single instance.
Do not blindly follow every recommendation. Check the peak metrics, not the average. If CPU averages 5% but spikes to 80% during a nightly job, the larger instance might be justified. But in most cases, small team workloads run significantly oversized because the original provisioner did not want to risk running out of capacity.
Day 4: Stop non-production environments outside business hours
Dev and staging environments should not run 24/7. If your team works 8am to 6pm, that is 10 hours of active use. Running 24 hours means you are paying for 14 hours of idle time per day, plus full weekends.
A simple Lambda function triggered by EventBridge Scheduler can stop tagged instances at 7pm and start them at 8am on weekdays:
# Example EventBridge schedule rule (stop at 7pm UTC on weekdays)
{
"ScheduleExpression": "cron(0 19 ? * MON-FRI *)",
"State": "ENABLED",
"Targets": [{
"Arn": "arn:aws:lambda:region:account:function:stop-dev-instances",
"Id": "StopDevInstances"
}]
}
# The Lambda function:
import boto3
ec2 = boto3.client('ec2', region_name='us-east-1')
def lambda_handler(event, context):
ec2.stop_instances(
InstanceIds=ec2.describe_instances(
Filters=[
{'Name': 'tag:Environment', 'Values': ['dev', 'staging']},
{'Name': 'instance-state-name', 'Values': ['running']}
]
)['Reservations'][0]['Instances'][0]['InstanceId'] # simplified
)Running 50 hours per week instead of 168 cuts the cost of non-production compute by 70%.
Day 5: Switch stable workloads to Reserved Instances or Savings Plans
If you have compute that you know will run for the next 12 months, commit to it. A 1-year Reserved Instance for an m5.large in us-east-1 costs $0.096/hour versus $0.096/hour on-demand... I mean $0.053/hour vs $0.096/hour. That is a 44% discount for the same capacity, just with a commitment.
Compute Savings Plans are more flexible: you commit to a dollar amount of compute per hour and the discount applies across any instance type or region. If you are not sure exactly which instances you will need next year, Savings Plans is the safer bet.
In Cost Explorer, go to Savings Plans → Recommendations. AWS will model your last 30 days of usage and show exactly how much you could save.
What 30% looks like in practice
A real example from a small team account I looked at: $520/month bill. After one week:
- Deleted 47 old snapshots: -$28/month
- Released 4 unattached Elastic IPs: -$14.40/month
- Downsized 2 staging instances: -$84/month
- Added stop/start schedule to dev environment: -$62/month
- Switched 1 production instance to 1-year RI: -$41/month
Total: $229.40/month in savings. 44% reduction. No code changes. No downtime. Just looking at the bill carefully and cleaning up what had drifted.
$ run-audit --your-account
I have done this process on enough accounts to know the 30% number is real. If you want it done on yours without spending a week on it yourself, I can take a look.
$ ./request-cost-review.sh →