Terraform Cost Optimization for AWS - Reduce Your Cloud Bill

Key Takeaway

Practical Terraform patterns to reduce AWS costs: right-sizing, spot instances, scheduling, and reserved capacity. Step-by-step guide with code examples and ...

Table of Contents

Reduce AWS Costs With Terraform

Cloud bills grow fast. These Terraform patterns help you build cost-aware infrastructure from the start.

1. Right-Size Instances

variable "instance_sizes" {
  default = {
    dev     = "t3.micro"
    staging = "t3.small"
    prod    = "t3.large"
  }
}

resource "aws_instance" "app" {
  instance_type = var.instance_sizes[terraform.workspace]
}

2. Use Spot Instances for Non-Critical Workloads

resource "aws_spot_instance_request" "batch" {
  ami                    = data.aws_ami.ubuntu.id
  instance_type          = "c5.xlarge"
  spot_price             = "0.05"
  wait_for_fulfillment   = true
  spot_type              = "one-time"

  tags = { Name = "batch-processor" }
}

Mixed ASG (On-Demand + Spot)

resource "aws_autoscaling_group" "app" {
  mixed_instances_policy {
    instances_distribution {
      on_demand_base_capacity                  = 1
      on_demand_percentage_above_base_capacity = 25
      spot_allocation_strategy                 = "capacity-optimized"
    }
    launch_template {
      launch_template_specification {
        launch_template_id = aws_launch_template.app.id
      }
      override {
        instance_type = "t3.medium"
      }
      override {
        instance_type = "t3a.medium"
      }
    }
  }
}

3. Schedule Non-Production Resources

# Stop dev instances at night
resource "aws_autoscaling_schedule" "scale_down" {
  autoscaling_group_name = aws_autoscaling_group.dev.name
  scheduled_action_name  = "scale-down-night"
  recurrence             = "0 20 * * MON-FRI"
  desired_capacity       = 0
  min_size               = 0
  max_size               = 0
}

resource "aws_autoscaling_schedule" "scale_up" {
  autoscaling_group_name = aws_autoscaling_group.dev.name
  scheduled_action_name  = "scale-up-morning"
  recurrence             = "0 8 * * MON-FRI"
  desired_capacity       = 2
  min_size               = 1
  max_size               = 4
}

4. Use S3 Lifecycle Rules

resource "aws_s3_bucket_lifecycle_configuration" "logs" {
  bucket = aws_s3_bucket.logs.id

  rule {
    id     = "archive-old-logs"
    status = "Enabled"

    transition {
      days          = 30
      storage_class = "STANDARD_IA"
    }
    transition {
      days          = 90
      storage_class = "GLACIER"
    }
    expiration {
      days = 365
    }
  }
}

5. NAT Gateway Alternatives

NAT Gateways cost ~$32/month + data transfer. For dev environments:

# Use a NAT instance instead (~$3/month with t3.nano)
resource "aws_instance" "nat" {
  count         = terraform.workspace == "prod" ? 0 : 1
  ami           = data.aws_ami.nat_instance.id
  instance_type = "t3.nano"
  source_dest_check = false
}

Cost Estimation in CI/CD

Add Infracost to your pipeline:

infracost breakdown --path . --format table

Learn More

🚀

Level Up Your Terraform Skills

Hands-on courses, books, and resources from Luca Berton

Luca Berton
Written by

Luca Berton

DevOps Engineer, AWS Partner, Terraform expert, and author. Creator of Ansible Pilot, Terraform Pilot, and CopyPasteLearn.