Rost CAMP

AWS Cost Optimization: 8 Steps to Cut Your Bill

By Rostyslav Myronenko, holder of 14 active AWS certifications.
. 11 min read

Most AWS bills grow through hundreds of small, reasonable decisions: an instance sized for a launch that never needed it, a NAT gateway carrying traffic it shouldn't, snapshots nobody remembers creating, a Savings Plan bought for an architecture that has since changed.

AWS cost optimization is finding those decisions, fixing the ones that matter and building habits so the bill doesn't drift back up. I go through a bill in a fixed order and this guide follows it: read the bill, fix the biggest items, then make the savings stick. If you need to reduce your AWS bill this quarter, steps 2 to 4 are where most of the money is.

The first breakdown of a bill tends to raise questions nobody on the team can answer straight away: which team owns the biggest EC2 line, why data transfer is in the top five at all, what a usage type like EUC1-NatGateway-Bytes is and why it costs that much. Answering them is most of step 1.

Step 1: Understand where the money goes

Before changing anything, get spend broken down by service, account, environment and team. Without that breakdown you end up optimizing whatever is easiest to see instead of whatever is biggest.

Use Cost Explorer for the first pass

AWS Cost Explorer answers the first questions: which services make up most of the bill, which accounts or environments are growing fastest, and which usage types dominate inside those services (EC2 instance hours versus EBS versus data transfer, for example).

In most bills a handful of services make up the large majority of spend. Start there and leave the long tail for later.

Use the Cost and Usage Report for detail

For anything past the first pass, use the AWS Cost and Usage Report (CUR). It has line-item detail you can query with Athena or load into your own tools, and it's how you find individual resources, hourly patterns and what your commitments are actually doing.

Tag for ownership

Costs without an owner don't get optimized, so agree on a small set of cost allocation tags and enforce them on new resources. Imperfect tagging is fine at the start, as long as the biggest lines have a name next to them.

A minimum scheme I'd start with has three tags: team (who pays), service (what it is) and environment (prod, staging, dev). If you use Terraform, set them once per provider with default_tags, so every resource the provider creates carries them without anyone remembering:

provider "aws" {
  region = "eu-central-1"

  default_tags {
    tags = {
      team        = "payments"
      service     = "checkout-api"
      environment = "prod"
    }
  }
}

Then add a tag policy in AWS Organizations to standardize the keys and allowed values, and activate the tags as cost allocation tags. If the resources were already tagged before activation, the management account can backfill the billing data for up to 12 months. Resources created outside Terraform still need a backstop: an SCP that denies creation without the tags works for the services that support tag-on-create. Roll it out one account at a time, because it breaks every pipeline that doesn't tag yet.

Step 2: Fix compute

For most companies compute is the largest part of the bill: EC2, containers and Lambda.

Right-size over-provisioned instances

Instances get sized for peak load, for a migration estimate or just "to be safe", and then nobody revisits them. Check CPU, memory and network utilization over a representative period, and downsize where the headroom is consistent.

AWS Compute Optimizer makes recommendations for EC2, Auto Scaling groups, EBS, Lambda and ECS on Fargate. I treat its output as a shortlist to investigate. Memory metrics need the CloudWatch agent, and some workloads are sized for reasons the metrics don't show.

Move to Graviton where it fits

AWS Graviton (Arm-based) instances generally give better price-performance than comparable x86 instances. For managed services the switch is mostly configuration; for your own applications it depends on the runtime and the native dependencies.

A sensible order is managed services first (RDS, Aurora, ElastiCache, OpenSearch), then Lambda functions, where the architecture is a single setting, then containers, then self-managed EC2 fleets. The blockers are nearly always outside your own code: a native library or Lambda layer with no arm64 build, a container image built for x86 only (a multi-arch build with docker buildx fixes that), CI runners that can't build or test Arm images, and third-party agents for monitoring or security that don't ship an Arm version. Check those four before you estimate the work.

Use Spot for interruptible work

Spot Instances run on spare EC2 capacity at a steep discount and can be interrupted at short notice. Batch jobs, CI/CD runners, stateless workers and fault-tolerant container workloads handle that well. Databases, and anything else that can't survive an interruption, don't.

Turn off what doesn't need to run

Dev, test and staging environments often run 24/7 and get used during working hours only. Scheduling non-production resources to stop overnight and at weekends is about the simplest saving there is.

Step 3: Cover steady usage with commitments

Once compute is right-sized, cover the steady baseline with commitments. Commit before right-sizing and you lock the waste in.

  • Savings Plans for EC2, Fargate, Lambda, SageMaker and managed databases. The AWS Savings Plans guide covers which type to buy and how to size it.
  • Reserved Instances where they still fit better, such as capacity reservations or services with no Savings Plan.
  • A private pricing agreement once spend is large and predictable enough. See how to negotiate an AWS PPA contract.

For all three, commit to your baseline, let the peaks run On-Demand, and check coverage and utilization every month.

Step 4: Fix storage

Storage costs creep up, because nothing breaks when you keep data you don't need.

Amazon S3

  • Add lifecycle policies to move or expire data that's rarely read.
  • Use S3 Intelligent-Tiering for data with unknown or changing access patterns, so objects move between access tiers on their own.
  • Clean up incomplete multipart uploads and old object versions in versioned buckets.
  • Look at request costs as well as storage. Some workloads spend more on requests than on the bytes they store.

Amazon EBS

Migrate gp2 volumes to gp3. gp3 lets you set IOPS and throughput separately from volume size and is generally cheaper per GB; just check that the performance settings match the workload. Delete unattached volumes once you've confirmed nobody needs them, and look at snapshot retention, because old snapshots from deleted instances are a common source of forgotten spend.

One that catches teams out: by default, deregistering an AMI doesn't delete the EBS snapshots behind it. Pipelines that bake a new AMI on every release leave a snapshot trail that nobody owns and nobody can trace back to anything running. The cleanup step in the pipeline should deregister old AMIs with the --delete-associated-snapshots option, so the snapshots go at the same time.

Step 5: Fix data transfer and networking

Data transfer is the part of the bill teams understand least, and the default Cost Explorer views don't make it easy to see.

The usual sources:

  • NAT gateway processing charges. Traffic from private subnets to S3 or DynamoDB often goes through a NAT gateway. Gateway VPC endpoints for S3 and DynamoDB avoid those processing charges for that traffic.
  • Cross-AZ traffic. Chatty services spread across Availability Zones pay for traffic in both directions. Keep high-volume communication inside one AZ where your availability requirements allow it.
  • Internet egress. Serving content straight from S3 or EC2 instead of through CloudFront can cost more, depending on your traffic.
  • Cross-Region replication and backups that nobody looked at again after setting them up.

To find them, filter Cost Explorer or the CUR on usage types containing DataTransfer and NatGateway, grouped by account and resource.

Step 6: Fix databases

Managed databases are often the second-largest line after compute. Right-size instances from CloudWatch metrics the same way as EC2, and remove idle or forgotten databases, including read replicas nobody queries. For spiky or low, intermittent load, Aurora Serverless or DynamoDB on-demand can be cheaper than a provisioned instance. Check backup retention and snapshot copies too, and cover steady database usage with Database Savings Plans or Reserved Instances.

Step 7: Make it stick

A one-off cleanup saves money once. Without follow-up, most bills drift back within months as new services launch and nobody is watching.

Set up guardrails

Set up AWS Budgets with alerts per account or team, turn on AWS Cost Anomaly Detection to catch spikes early, and enforce tags on new resources so ownership doesn't decay.

Build a FinOps rhythm

FinOps is the practice of making cloud cost a shared responsibility between engineering, finance and product. For most teams it comes down to four habits:

  1. A monthly cost review with the people who own the biggest lines.
  2. Commitment management, with coverage and utilization checked every month.
  3. Cost as a design input, so new architecture decisions come with an estimate of what they'll cost to run.
  4. Unit costs: cost per customer, transaction or environment, tracked alongside the total bill.

The monthly review doesn't need to be long. An hour is plenty if the numbers are prepared beforehand. Invite the owners of the five biggest lines, one engineering lead who can say yes to changes, and someone from finance who knows the budget. A workable agenda:

  1. Last month against budget and forecast, in one line each.
  2. The biggest movers: the lines that grew or shrank the most, and why.
  3. Anomalies that fired, and whether they were real.
  4. Commitments: utilization, coverage, and anything expiring in the next 90 days.
  5. Open actions from last month.

The output is a short list of actions, each with an owner and a date. If a month's review produces no actions, that's a good month, and the meeting can finish early.

If you'd rather not run that rhythm yourself, the retainer on my FinOps consulting page includes a written monthly review of architecture and spend.

Step 8: Choose the cheaper service, even when AWS's examples don't

AWS samples, workshops and reference architectures use the service built for the job, which is rarely the cheapest one that would do it. Once the bill is under control, the next savings come from design choices like that. Key-value data is a good example.

DynamoDB is the default answer for key-value storage. S3 can do the same job: the object key is the key, the object is the value, and you read and write with GET and PUT. Which one is cheaper depends on the size of the values and how often you touch them. On-demand list prices in us-east-1, from the DynamoDB and S3 pricing pages (checked September 2026):

S3 StandardDynamoDB on-demand
Storage$0.023 per GB-month$0.25 per GB-month
Write$5.00 per million PUTs, any size$0.625 per million, per KB of item
Read$0.40 per million GETs, any size$0.125 per million, per 4 KB (half that for eventually consistent reads)

Storage is about eleven times cheaper in S3. Requests go the other way for small items: a DynamoDB write of up to 1 KB costs an eighth of an S3 PUT. Once a value passes about 8 KB, the S3 PUT becomes the cheaper write, and reads cross over at about 13 KB, or 26 KB if eventually consistent reads are enough.

Two monthly examples, ignoring the DynamoDB free tier:

  • 500 GB of 100 KB documents, with 5 million writes and 20 million eventually consistent reads: about $45 in S3 against about $470 in DynamoDB.
  • 20 GB of 1 KB items, with 50 million writes and 200 million eventually consistent reads: about $330 in S3 against about $50 in DynamoDB.

So S3 is the cheaper key-value store for large values that are written rarely, and DynamoDB stays cheaper for lots of small items that change often. Check what S3 gives up before you move anything. Median latency for small requests is in the tens of milliseconds, against DynamoDB's single digits. There are conditional writes but no transactions, no secondary indexes and no queries, and expiry works through lifecycle rules in whole days rather than a per-item TTL. Each prefix also handles about 3,500 writes and 5,500 reads per second before you need to spread keys across prefixes (S3 performance guidelines). If latency matters, S3 Express One Zone gives single-digit millisecond access and request costs up to 80% lower than S3 Standard, with storage that costs several times more.

S3 Tables don't fit this use case. They hold Apache Iceberg tables for analytics, you read them through a query engine such as Athena instead of fetching a key, and they add monitoring and compaction fees on top of storage.

The same check is worth running on other defaults in reference diagrams, such as a NAT gateway carrying traffic that a gateway VPC endpoint would carry for free (see step 5).

Where to start

Most lists of AWS cost optimization best practices run much longer than this guide. If you only do three things this month:

  1. Find your top five cost lines and put an owner next to each.
  2. Right-size or remove the obvious waste in those five lines.
  3. Check your Savings Plans coverage and utilization.

FAQ

What are the main AWS cost optimization strategies?

Understand the bill and give each big line an owner, right-size and clean up compute, cover steady usage with Savings Plans or Reserved Instances, fix storage and data transfer, and keep a monthly review and anomaly alerts running afterwards.

What are the pillars of AWS cost optimization?

Cost optimization is one of the six pillars of the AWS Well-Architected Framework. Within it, AWS groups the work into five areas: practice Cloud Financial Management, expenditure and usage awareness, cost-effective resources, manage demand and supply resources, and optimize over time.

Is AWS Cost Optimization Hub free?

Yes. AWS offers Cost Optimization Hub at no additional charge. It pulls in recommendations from other services, such as Compute Optimizer, which you have to opt in to separately.

How much can I save on AWS?

It depends on how much optimization has already been done. AWS doesn't publish a typical figure, and generic percentages from vendors are a poor guide to your bill. The only reliable number comes from reviewing your actual usage.

Should I use a tool or a consultant for AWS cost optimization?

Tools are good at finding recommendations, continuously. The hard part is deciding which changes are safe, putting them in order and implementing them in your infrastructure. A consultant helps most when nobody on the team has the time or the experience to do that.

Getting your AWS bill down

AWS cloud cost optimization comes in two parts: a short, intensive cleanup, then a monthly habit that stops the savings leaking back.

If you'd rather do the cleanup with someone, my AWS Savings Implementation Sprint is a fixed 4–6 week engagement on your actual bill. I implement the changes myself, and part of the fee is a share of the savings measured on your bill.

More from the blog