Cloud Tech
DevOpsIntermediate

Cloud Cost Optimization

Why idle and over-provisioned resources leak most cloud spend, and the levers (rightsizing, commitment discounts, autoscaling) that fix it.

Reviewed Jul 22, 2026Victor Nwoke4 min read

Written and maintained by Victor Nwoke. Technical behavior is reviewed against the primary references listed on this page.

Overview

Most cloud cost problems aren't about usage being inherently expensive; they're about provisioned capacity sitting idle or oversized relative to what's actually needed, compounding silently because nothing forces a team to revisit a sizing decision made months ago. Cost optimization is the discipline of closing that gap: rightsizing resources to observed load, matching pricing models (on-demand, committed-use, spot) to how predictable and interruption-tolerant a workload actually is, and eliminating genuinely idle spend (unattached storage volumes, forgotten test environments) that provides zero value at any size. None of this is a one-time project, usage patterns and workloads change, so the waste that gets cleaned up today starts accumulating again immediately. Idle compute and storage are the obvious leaks; data-processing charges hidden inside network architecture are the less obvious kind, see The AWS Bill Spiked and Nobody Had Launched Anything New for a real NAT Gateway cost investigation.

Quick Reference

LeverAddressesTypical savings
RightsizingOver-provisioned steady-state resourcesOften the single biggest win
Committed-use discountsPredictable, continuous workloads30–60% vs. on-demand
Spot/preemptible instancesInterruption-tolerant, flexible workloadsUp to 70–90% vs. on-demand
AutoscalingLoad-variable workloadsAvoids paying for unused peak capacity
Idle-resource cleanupUnattached volumes, forgotten environments100% of that specific waste

Syntax

hcl
# Autoscaling tied to actual observed load, not a static guess
resource "aws_autoscaling_policy" "scale_up" {
  autoscaling_group_name = aws_autoscaling_group.app.name
  policy_type             = "TargetTrackingScaling"
  target_tracking_configuration {
    predefined_metric_specification {
      predefined_metric_type = "ASGAverageCPUUtilization"
    }
    target_value = 60.0
  }
}

Examples

bash
# Find genuinely idle spend - an unattached volume costs the same
# whether it's attached to a running instance or sitting orphaned.
aws ec2 describe-volumes --filters Name=status,Values=available \
  --query 'Volumes[*].[VolumeId,Size,CreateTime]'
bash
# NAT Gateway data processing is billed per GB and doesn't show up as a
# line item until Cost Explorer, this pulls the actual bytes flowing
# through a specific gateway over the last day.
aws cloudwatch get-metric-statistics \
  --namespace AWS/NATGateway --metric-name BytesOutToDestination \
  --dimensions Name=NatGatewayId,Value=nat-0123456789abcdef0 \
  --start-time "$(date -u -d '1 day ago' +%Y-%m-%dT%H:%M:%S)" \
  --end-time "$(date -u +%Y-%m-%dT%H:%M:%S)" --period 86400 --statistics Sum

Tag everything, from day one

Cost attribution (which team, which project, which environment) is what makes rightsizing and cleanup decisions actionable at all. Retrofitting tags onto years of untagged resources is far more expensive than enforcing them at creation time.

Visual Diagram

Common Mistakes

  • Provisioning for peak load and never scaling back down, leaving steady-state capacity idle the vast majority of the time.
  • Using on-demand pricing for a workload that's been running continuously and predictably for months, the exact case committed-use discounts are built for.
  • Leaving orphaned resources (unattached storage volumes, unused load balancers, forgotten test environments) running indefinitely because nothing alerts on pure waste the way it alerts on an outage.
  • Setting autoscaling minimums far above actual baseline load "to be safe," which quietly defeats much of autoscaling's cost benefit.
  • Routing traffic to AWS services like S3 or DynamoDB through a NAT Gateway instead of a VPC Gateway Endpoint. NAT Gateway bills a per-GB data processing charge on top of its hourly cost, on high-volume traffic this can dwarf the compute bill it's attached to, while a Gateway Endpoint for S3/DynamoDB traffic costs nothing extra and keeps that traffic off the NAT Gateway entirely.

Performance

  • Aggressive cost-cutting can trade away real performance margin, rightsizing too tightly against average load leaves no headroom for legitimate spikes, causing degradation exactly when it matters most.
  • Spot/preemptible instances introduce interruption as a real operational concern; workloads using them need to handle reclamation gracefully (checkpointing, retry logic) or the "savings" show up as reliability cost instead.
  • Committed-use discounts lock in capacity assumptions for their term, a workload that shrinks significantly during that period turns a discount into paid-for-but-unused capacity, so commitments should track only genuinely stable baseline usage.

Best Practices

  • Tag every resource with owner/team/environment from creation, since cost attribution is what makes every other optimization actionable.
  • Rightsize on a recurring cadence using actual utilization data, not a one-time pass, usage patterns drift.
  • Match pricing model to workload predictability: committed-use for stable steady-state, spot for interruption-tolerant and flexible, on-demand for genuinely unpredictable or short-lived needs.
  • Set up automated detection for idle resources (unattached volumes, empty load balancers) so waste gets caught continuously, not only during periodic manual audits.
  • I use VPC Gateway Endpoints (free, no data-processing charge) for S3/DynamoDB traffic instead of routing it through a NAT Gateway; reserve NAT Gateway for traffic that genuinely needs to reach the public internet.
  • I check a NAT Gateway's BytesOutToDestination CloudWatch metric before a bill surprise forces the investigation, per-GB processing charges are invisible in the console until they show up as a lump sum in Cost Explorer.

Interview questions

Why is "rightsizing" usually the highest-leverage cost optimization, and why do teams under-invest in it?
Rightsizing means matching provisioned capacity (instance size, allocated memory) to actual observed usage, and it typically has the biggest impact because most cloud resources are provisioned for a peak or a guess, then never revisited, meaning steady-state waste compounds every hour, every day, indefinitely. Teams under-invest in it because it requires ongoing measurement and periodic action, competing for attention against feature work that has more visible payoff, and because a resource that's "working fine" doesn't generate the same urgency as one that's broken, even if it's costing several times what it needs to.
What is the difference between a reserved/committed-use discount and a spot/preemptible instance, and when does each make sense?
A committed-use discount (reserved instances, savings plans) trades a usage commitment, a fixed amount of spend or capacity over a term, typically one or three years, for a significant price reduction on workloads you know will run continuously. Spot/preemptible instances offer a much steeper discount in exchange for the provider being able to reclaim the capacity with little notice, making them suitable only for interruption-tolerant workloads (batch jobs, stateless workers, CI runners) rather than anything requiring guaranteed uptime. Committed-use addresses predictable steady-state load; spot addresses flexible, interruption-tolerant load, using either for the wrong workload type either wastes the discount or causes outages.
Why doesn't autoscaling alone guarantee cost efficiency?
Autoscaling matches capacity to load, but only within whatever floor and configuration a team sets, a minimum instance count set too high, overly conservative scale-down thresholds, or scaling policies that react slowly to load drops all leave a workload over-provisioned even with autoscaling technically "on." Autoscaling is necessary but not sufficient: it needs to be tuned against real traffic patterns and revisited periodically, the same way static rightsizing does, or it just becomes a more complex way to still be over-provisioned most of the time.

References

ShareXLinkedInReddit
Was this page helpful?
Suggest an improvement