The fastest path to meaningful cloud cost cuts on AWS is not a single tool or a reserved instance purchase. It is a repeatable process that puts cost data in front of the engineers who create the spend, attaches accountability to teams, and treats optimization as a continuous engineering discipline rather than a quarterly fire drill. In this post I lay out a practical FinOps framework you can adopt incrementally, starting with visibility and ending with automated guardrails. If you do nothing else, start by tagging your resources and turning on Cost and Usage Reports. Everything else builds on that foundation.
Why AWS Bills Spiral (And Why Traditional Fixes Fail)
Most teams I work with do not overspend because they are careless. They overspend because the people making architectural decisions never see the financial consequences. An engineer picks an r5.4xlarge because it was in a Terraform module someone copied two years ago. A test environment runs 24/7 because nobody owns shutting it down. A data pipeline writes to S3 Standard when the objects are read once and never touched again.
The traditional fix is a top-down cost review: finance flags a scary number, leadership demands savings, and engineering scrambles to right-size a few instances. This works once. It does not stick, because the incentives and information never change. FinOps solves this by making cost a shared, continuous engineering signal.
The three pillars I organize every engagement around are:
- Inform — give teams accurate, timely, granular cost visibility.
- Optimize — reduce waste and improve rate efficiency.
- Operate — embed cost accountability into how teams build and run software.
Phase 1: Inform — You Cannot Cut What You Cannot See
Fix your tagging before anything else
Untagged spend is invisible spend. Define a small, mandatory tag policy and enforce it. I keep the required set short so teams actually comply:
owner— the team or squad, not an individualenvironment—prod,staging,devcost-center— for chargeback or showbackservice— the application or workload name
Enforce tags at provision time rather than cleaning up after. With AWS Organizations you can use Tag Policies, and in Terraform you can apply defaults at the provider level:
provider "aws" {
region = "us-east-1"
default_tags {
tags = {
environment = var.environment
cost-center = var.cost_center
owner = var.team
}
}
}
Add a Service Control Policy or a terraform plan policy check that rejects resources missing required tags. The goal is that untagged infrastructure simply cannot reach production.
Turn on the Cost and Usage Report
Cost Explorer is fine for a first look, but the Cost and Usage Report (CUR) is the source of truth. Deliver it to S3, query it with Athena, and build dashboards your engineers actually open. A basic query to find your top spend by service and team looks like this:
SELECT
line_item_product_code AS service,
resource_tags_user_owner AS team,
SUM(line_item_unblended_cost) AS cost
FROM cur_table
WHERE line_item_usage_start_date >= date_add('day', -30, current_date)
GROUP BY 1, 2
ORDER BY cost DESC
LIMIT 25;
The single most valuable output of Phase 1 is a per-team cost trend that lands in a Slack channel every Monday. When teams see their own numbers moving, behavior changes without a mandate.
Phase 2: Optimize — Where the Cloud Cost Cuts Actually Happen
Optimization splits into two categories: reducing usage (do less) and improving rate (pay less for the same thing). Tackle usage first. It is where the durable savings live, and rate commitments made on top of a bloated baseline just lock in waste.
Eliminate waste
Start with the things nobody will miss:
- Idle and orphaned resources. Unattached EBS volumes, old snapshots, unused Elastic IPs, and load balancers with no targets. AWS Trusted Advisor and Cost Explorer's rightsizing recommendations surface most of these.
- Non-production schedules. Dev and staging environments rarely need to run overnight or on weekends. Scheduling them off can cut those account costs substantially. A simple EventBridge rule plus a Lambda that stops tagged instances handles this:
import boto3
def handler(event, context):
ec2 = boto3.client("ec2")
instances = ec2.describe_instances(
Filters=[
{"Name": "tag:environment", "Values": ["dev", "staging"]},
{"Name": "instance-state-name", "Values": ["running"]},
]
)
ids = [
i["InstanceId"]
for r in instances["Reservations"]
for i in r["Instances"]
]
if ids:
ec2.stop_instances(InstanceIds=ids)
- Over-provisioned instances. Use CloudWatch metrics and Compute Optimizer to right-size. Look for instances sitting under 20% CPU and memory utilization for weeks.
Fix storage tiering
S3 costs creep quietly. Apply lifecycle policies and let S3 Intelligent-Tiering move cold objects automatically:
{
"Rules": [{
"ID": "archive-old-logs",
"Status": "Enabled",
"Filter": { "Prefix": "logs/" },
"Transitions": [
{ "Days": 30, "StorageClass": "STANDARD_IA" },
{ "Days": 90, "StorageClass": "GLACIER" }
],
"Expiration": { "Days": 365 }
}]
}
Do the same for EBS: migrate gp2 volumes to gp3, which is cheaper and lets you provision IOPS independently.
Improve your rate
Only after usage is trimmed should you commit to discounts:
- Savings Plans and Reserved Instances for steady-state compute. Compute Savings Plans are the most flexible because they apply across instance families and regions.
- Spot Instances for fault-tolerant, interruptible workloads like batch processing, CI runners, and stateless web tiers behind autoscaling.
- Graviton (ARM) instances, which often deliver better price-performance for compatible workloads. Test your build first, but many services run on Graviton with a recompile.
A sound commitment strategy covers your reliable baseline with Savings Plans and lets Spot and on-demand absorb the peaks. Do not commit to 100% of current usage. Cover the floor you are confident about.
If you want help designing the automation and commitment strategy across accounts, our cloud and infrastructure capabilities cover exactly this kind of build-out.
Phase 3: Operate — Make Cost a Continuous Practice
Set budgets and anomaly alerts
Use AWS Budgets with alerts routed to the owning team, not a central inbox. Pair that with Cost Anomaly Detection, which uses machine learning to flag unusual spikes so you catch a runaway job in hours rather than at month-end.
Shift cost left into engineering
The highest-leverage move is showing cost impact before deploy. Tools like Infracost can annotate a pull request with the projected monthly cost delta of an infrastructure change:
# .github/workflows/infracost.yml
- name: Infracost breakdown
run: |
infracost breakdown --path=. \
--format=json --out-file=/tmp/infracost.json
infracost comment github --path=/tmp/infracost.json \
--repo=$GITHUB_REPOSITORY --pull-request=$PR_NUMBER \
--github-token=$GITHUB_TOKEN
When a reviewer sees "this change adds $4,200/month," the conversation happens before the spend exists.
Assign real ownership
FinOps fails when it lives entirely in finance or entirely in a platform team. Establish a lightweight working group with representation from engineering, platform, and finance. Review the top movers monthly, set optimization targets per team, and celebrate reductions the way you celebrate shipping features. Different sectors have different cost profiles, and if you operate in a regulated or data-heavy space, the tradeoffs around retention and residency change the math. We account for those constraints across the industries we support.
A Realistic 90-Day Rollout
If you are starting from zero, sequence the work so you get wins early and avoid boiling the ocean:
- Weeks 1-2: Tagging policy defined and enforced in IaC. CUR delivered to S3, Athena queries running.
- Weeks 3-4: Weekly per-team cost dashboards live. Kill obvious waste: orphaned volumes, idle load balancers.
- Weeks 5-8: Non-prod scheduling, storage lifecycle policies, right-sizing pass. Budgets and anomaly detection configured.
- Weeks 9-12: Savings Plans coverage on the confirmed baseline. Infracost in CI. Monthly FinOps review scheduled and owned.
The point is momentum. Ship the tagging and visibility work first, prove savings, then earn the mandate for the harder architectural changes.
FAQ
How much can we realistically save with a FinOps framework?
Savings depend heavily on your starting maturity. Teams with untagged, unmonitored spend usually find substantial waste in idle resources and non-prod environments alone. I avoid promising a fixed percentage, because the honest answer is that it scales with how much waste currently exists. Measure your own baseline first.
Should we buy Reserved Instances or Savings Plans first?
Neither, until you have trimmed usage. Committing to a discount on over-provisioned infrastructure just locks in that waste for one to three years. Right-size and eliminate idle resources first, then cover your stable baseline with Compute Savings Plans for flexibility.
Do we need a dedicated FinOps team?
Not to start. A cross-functional working group with clear ownership and a monthly review cadence is enough for most mid-sized organizations. Dedicated roles make sense once cloud spend is large enough that continuous optimization pays for the headcount.
How do we reduce cloud spend without slowing engineering down?
Automate the guardrails so cost awareness is passive, not a manual chore. Default tags in IaC, PR cost annotations, scheduled shutdowns, and anomaly alerts all work without adding steps to an engineer's day. The goal is to make the cost-efficient path the default path.
What is the difference between showback and chargeback?
Showback reports each team's cloud costs for visibility without moving money between budgets. Chargeback actually bills the cost back to the team or business unit. Most organizations start with showback to build accountability, then adopt chargeback once tagging and cost allocation are trustworthy.
Production-grade cloud, software, and engineering teams for scaling companies.