DEV Community

devtocash
devtocash

Posted on Originally published at devtocash.com

AWS Cost Optimization: 15 Proven Ways to Cut Your Cloud Bill

💡 Originally published on devtocash.com — where this guide stays updated. I write hands-on DevOps/SRE deep-dives there weekly.

Introduction

AWS bills have a way of creeping up. That t2.micro becomes a c5.xlarge, the S3 bucket accumulates terabytes of forgotten data, and suddenly your monthly invoice is five figures.

The good news: most AWS cost optimization is low-hanging fruit. You don't need to re-architect your application. You need to apply the right tools and develop the right habits.

Here are 15 proven strategies, organized by service category, with concrete commands you can run today.

Compute: EC2, Lambda, and Containers

1. Rightsize Your EC2 Instances

AWS offers 700+ instance types. The one you picked three years ago is probably wrong for your current workload.

# Install AWS Compute Optimizer
aws compute-optimizer get-ec2-instance-recommendations \
  --query 'instanceRecommendations[*].[instanceArn,currentInstanceType,recommendationOptions[0].instanceType]' \
  --output table
Enter fullscreen mode Exit fullscreen mode

Common findings:

  • 60% of instances are over-provisioned by 2x or more
  • Switching from Intel to AMD (e.g., m5.large to m5a.large) saves 10%
  • Switching to ARM (Graviton, e.g., m6g.large) saves 20-40%

2. Use Spot Instances for Fault-Tolerant Workloads

Spot instances cost 60-90% less than on-demand:

# Request Spot Instance
aws ec2 request-spot-instances \
  --spot-price "0.03" \
  --instance-count 1 \
  --launch-specification file://spec.json
Enter fullscreen mode Exit fullscreen mode

Good candidates: CI/CD runners, batch processing, stateless web workers, dev/test environments. Use EC2 Auto Scaling groups with mixed instance policies to automatically fall back to on-demand when Spot is interrupted.

3. Graviton (ARM) Migration

ARM-based Graviton instances deliver 20-40% better price-performance:

# Multi-arch Docker build
FROM --platform=linux/arm64 node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --production
COPY . .
CMD ["node", "server.js"]
Enter fullscreen mode Exit fullscreen mode

Build and push:

docker buildx build --platform linux/amd64,linux/arm64 -t myapp:latest --push .
Enter fullscreen mode Exit fullscreen mode

4. Lambda: Right-Size Memory

Lambda charges per GB-second. Doubling memory doubles cost—but also doubles CPU. Run load tests at different memory settings:

aws lambda update-function-configuration \
  --function-name my-function \
  --memory-size 1024
Enter fullscreen mode Exit fullscreen mode

Often, 1-2GB hits the sweet spot. Use AWS Lambda Power Tuning to find the optimal memory configuration automatically.

5. Scheduled Start/Stop for Non-Production

Dev and staging environments don't need to run 24/7:

# Lambda function to stop instances tagged Environment=staging at 8 PM
import boto3

def lambda_handler(event, context):
    ec2 = boto3.client('ec2')
    instances = ec2.describe_instances(
        Filters=[
            {'Name': 'tag:Environment', 'Values': ['staging', 'dev']},
            {'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)
        print(f"Stopped: {ids}")
Enter fullscreen mode Exit fullscreen mode

Schedule this Lambda via EventBridge cron—saves ~65% on non-prod compute.

Storage: S3, EBS, and Backups

6. S3 Lifecycle Policies

Automatically transition objects to cheaper storage classes:

{
  "Rules": [{
    "Id": "MoveToGlacier",
    "Status": "Enabled",
    "Transitions": [
      {"Days": 30, "StorageClass": "STANDARD_IA"},
      {"Days": 90, "StorageClass": "GLACIER_INSTANT_RETRIEVAL"}
    ],
    "Expiration": {"Days": 365}
  }]
}
Enter fullscreen mode Exit fullscreen mode
Storage Class Cost/GB Retrieval
S3 Standard $0.023 Instant
S3 Intelligent-Tiering Auto Instant
S3 Standard-IA $0.0125 Instant
S3 Glacier Instant $0.004 Milliseconds

7. Delete Unattached EBS Volumes

Every terminated EC2 instance can leave orphaned volumes:

aws ec2 describe-volumes \
  --filters Name=status,Values=available \
  --query 'Volumes[*].[VolumeId,Size,CreateTime]' \
  --output table
Enter fullscreen mode Exit fullscreen mode

Take snapshots of anything important, then delete:

aws ec2 delete-volume --volume-id vol-0abc123def456
Enter fullscreen mode Exit fullscreen mode

8. Clean Up Old Snapshots and AMIs

Snapshots accumulate silently:

aws ec2 describe-snapshots --owner-ids self \
  --query 'Snapshots[?StartTime<`2025-01-01`].[SnapshotId,StartTime,VolumeSize]' \
  --output table
Enter fullscreen mode Exit fullscreen mode

Set up AWS Backup with retention policies instead of manual snapshots.

Networking and Data Transfer

9. Use VPC Endpoints

Data transfer between S3 and EC2 within the same region is free—but only through VPC endpoints:

aws ec2 create-vpc-endpoint \
  --vpc-id vpc-xxx \
  --service-name com.amazonaws.us-east-1.s3 \
  --route-table-ids rtb-xxx
Enter fullscreen mode Exit fullscreen mode

Without endpoints, S3 traffic routes through NAT Gateways or Internet Gateways, incurring data transfer costs.

10. CloudFront for Content Delivery

Serve static assets through CloudFront—cheaper data transfer than S3 direct:

S3 direct: $0.09/GB (first 10TB)
CloudFront: $0.085/GB (US), $0.02/GB (reserved capacity)
Enter fullscreen mode Exit fullscreen mode

Plus, CloudFront caches reduce origin requests to S3, cutting those costs too.

Financial Tools and Governance

11. AWS Savings Plans

Commit to 1 or 3 years of compute usage for up to 72% savings:

aws savingsplans describe-savings-plans
Enter fullscreen mode Exit fullscreen mode

Compute Savings Plans apply to EC2, Lambda, and Fargate—far more flexible than Reserved Instances.

12. AWS Budgets and Alerts

Catch cost overruns before they surprise you:

aws budgets create-budget \
  --account-id 123456789012 \
  --budget file://budget.json \
  --notifications-with-subscribers file://notifications.json
Enter fullscreen mode Exit fullscreen mode

Set alerts at 50%, 80%, and 100% of monthly budget. Route to Slack via SNS + Lambda.

13. Enable Cost Explorer and Tag Everything

Tags are the foundation of cost attribution:

Environment: production | staging | development
Team: backend | frontend | data
Service: api-server | worker | database
CostCenter: engineering-001
Enter fullscreen mode Exit fullscreen mode

Without tags, you can't answer "who spent $5000 on EC2 last month?" Enable cost allocation tags in Billing Console and enforce tagging with SCPs or AWS Config rules.

14. Use Trusted Advisor

AWS Trusted Advisor (Business/Enterprise support) surfaces idle resources, underutilized instances, and unattached IPs:

aws support describe-trusted-advisor-check-result \
  --check-id <check-id> \
  --language en
Enter fullscreen mode Exit fullscreen mode

15. Implement FinOps Culture

Tools help, but culture matters more:

  • Showback first: Make costs visible before charging teams
  • Weekly cost reviews: 15-minute standup looking at the AWS bill
  • Cost-per-feature: Calculate how much each API endpoint or feature costs
  • Gamify savings: Track "money saved this month" alongside velocity metrics

Related Reading

Conclusion

You don't need to implement all 15 strategies at once. Start with the top three: rightsize EC2 instances, enable S3 lifecycle policies, and set up AWS Budgets. Those three alone typically cut 30-40% of cloud waste.

The key insight: AWS cost optimization is not a one-time project. It's a continuous practice—like monitoring or security. Build it into your weekly routine, and your cloud bill will thank you.


📌 Read the latest version of this guide — plus the full library of DevOps, SRE, Kubernetes, observability & cloud-cost guides — on devtocash.com.

Top comments (0)