← Back to list

Infracost Tutorial: Add Terraform Cost Estimates to GitHub PRs

Learn how to use Infracost, Terraform, and GitHub Actions to detect expensive cloud changes before deployment

Kirshi Yin in Curious Devs Corner · 2026-07-08 12:51 · 2 claps · 7.4 min read paywalled
#finops #terraform #devops #devops-tool #software-engineering
Open on Medium ↗
Wiki topics: ☁️ · DevOps & Cloud 🔓 · Open Source

Infracost Tutorial: Add Terraform Cost Estimates to GitHub PRs

Learn how to use Infracost, Terraform, and GitHub Actions to detect expensive cloud changes before deployment

Photo by Bermix Studio on Unsplash

Photo by Bermix Studio on Unsplash

In many teams, engineers create infrastructure without knowing the exact cost impact. For example, changing an EC2 instance from t3.medium to m7i.4xlarge.

What if your pull request could warn you before merging:

“This change will increase monthly costs by $840.”

Infracost solves this by adding cost visibility into the development workflow. It turns infrastructure changes into cost estimates during code review, so teams catch expensive decisions early instead of after deployment.

In this article, you’ll build a complete demo from scratch using Terraform, GitHub Actions, and Infracost. By the end, you’ll have automated PR cost diffs, FinOps policy checks, and cost guardrails running directly in your CI/CD pipeline.

You can access this story for free here.

New to Terraform? Before diving in, check out Terraform Quickstart— a beginner-friendly ebook that walks you through Terraform fundamentals so you can follow this tutorial with confidence.

Infracost Overview

FinOps is a practice that helps teams make informed decisions about cloud spending by connecting infrastructure work with cost visibility and accountability.

Infracost is a FinOps tool for Infrastructure as Code workflows. It integrates with tools like Terraform, OpenTofu, Terragrunt, AWS CloudFormation, and AWS CDK.

Instead of changing your workflow, it plugs into existing pipelines and shows the cost impact of infrastructure changes during development and code review. This helps teams catch expensive changes early and keep cloud spending under control.

Infracost uses public cloud pricing data from AWS, Azure, and Google Cloud to estimate monthly costs from your infrastructure definitions.

The core CLI is open source and free for individuals and small teams. Infracost Cloud adds pull request comments, policy checks, and governance features, with a free tier and paid plans for larger organizations that need advanced FinOps controls like dashboards, audit logs, and organization-wide policies.

A Complete Infracost Demo with Terraform and GitHub Actions

Prerequisites

  • Terraform CLI installed
  • A GitHub account
  • A free Infracost account (we’ll create it during setup)

The idea of this exercise

The workflow looks like this:

  1. A developer opens a PR with Terraform changes.
  2. GitHub Actions runs terraform plan for the pull request branch.
  3. Infracost reads the plan and calculates the cost diff vs the base.
  4. Infracost posts a comment on the PR showing the breakdown.
  5. If the cost increase exceeds your configured threshold, the pipeline fails — blocking the merge until a team lead reviews it.

Step 1 — Install Infracost and Get an API Key

Install the CLI:

curl -fsSL https://raw.githubusercontent.com/infracost/infracost/master/scripts/install.sh | sh
infracost --version

Then authenticate to get your free API key:

infracost auth login

This opens a browser. Follow the steps to sign up for free. You can also use your GitHub account. The key is stored locally and never expires on the free tier.

Step 2 — Create the Terraform Project

Create a working directory and add a simple main.tf with an EC2 instance and an RDS database. We’ll use mock AWS credentials since we only need to generate a Terraform plan and won’t apply anything.

Terraform still validates the provider during planning, but Infracost only reads the plan output. That makes mock credentials enough for this demo.

mkdir ~/infracost-demo && cd ~/infracost-demo

This is the content of the main.tf:

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }
}
provider "aws" {
  region = "us-east-1"
  skip_credentials_validation = true
  skip_requesting_account_id  = true
  skip_metadata_api_check     = true
  access_key                  = "mock_access_key"
  secret_key                  = "mock_secret_key"
}
resource "aws_instance" "web" {
  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = "t3.micro"
  root_block_device {
    tags = {
      Environment = "Stage"
      Service     = "web"
    }
  }
  tags = {
    Name        = "demo-web-server"
    Environment = "Stage"
    Service     = "web"
  }
}
resource "aws_db_instance" "postgres" {
  engine              = "postgres"
  instance_class      = "db.t3.medium"
  allocated_storage   = 100
  db_name             = "appdb"
  username            = "admin"
  password            = "notreal123"
  skip_final_snapshot = true
  tags = {
    Name        = "demo-postgres"
    Environment = "Stage"
    Service     = "database"
  }
}

In production environments, never hardcode database credentials in Terraform files. Use secret managers or CI/CD secret injection instead. We use a placeholder password here only for the demo.

Step 3 — See Your First Cost Breakdown Locally

Before wiring up GitHub Actions, let’s run Infracost locally so you understand what it produces.

terraform init
terraform plan -out=tfplan.binary
terraform show -json tfplan.binary > plan.json
infracost breakdown --path=plan.json

This provides a detailed, resource-by-resource cost estimate of your cloud infrastructure before you actually deploy it. You’ll see an output like this:

 Name                                                       Monthly Qty  Unit   Monthly Cost   

 aws_db_instance.postgres                                                                      
 ├─ Database instance (on-demand, Single-AZ, db.t3.medium)          730  hours        $52.56   
 └─ Storage (general purpose SSD, gp2)                              100  GB           $11.50   

 aws_instance.web                                                                              
 ├─ Instance usage (Linux/UNIX, on-demand, t3.micro)                730  hours         $7.59   
 └─ root_block_device                                                                          
    └─ Storage (general purpose SSD, gp2)                             8  GB            $0.80   

 OVERALL TOTAL                                                                       $72.45

Now let’s simulate a developer making an expensive change — upgrading both resources:

Edit main.tf and change these values:

  • instance_type = "t3.micro""t3.xlarge"
  • instance_class = "db.t3.medium""db.r5.2xlarge"

Then generate the new plan and run a diff:

# Create a new plan file for the updated infrastructure
terraform plan -out=tfplan2.binary
# Convert the binary plan into JSON format (required by Infracost)
terraform show -json tfplan2.binary > plan2.json

# Baseline cost (original configuration)
infracost breakdown --path=plan.json \
  --format=json \
  --project-name=demo \
  --out-file=infracost-base.json

# New cost after infrastructure changes
infracost breakdown --path=plan2.json \
  --format=json \
  --project-name=demo \
  --out-file=infracost-new.json

# Show cost difference between baseline and new plan
infracost diff --path=infracost-new.json --compare-to=infracost-base.json

The output shows exactly what changed and what it costs:

Project: demo
~ aws_db_instance.postgres
  +$677 ($64 → $742)
    ~ Database instance: db.t3.medium → db.r5.2xlarge  +$677
~ aws_instance.web
  +$114 ($8 → $122)
    ~ Instance usage: t3.micro → t3.xlarge  +$114
Monthly cost change for demo
Amount:  +$791 ($72 → $864)
Percent: +1,092%

Step 4 — Push to GitHub

Revert main.tf back to the small instance sizes (t3.micro and db.t3.medium) — this becomes your main branch baseline.

Add a .gitignore so plan files and state don't end up in git:

cat > .gitignore << 'EOF'
*.binary
*.json
*.html
.terraform/
.terraform.lock.hcl
EOF

Create a repo on GitHub, for example, infracost-demo. Then in your project’s directory run:

git init
git add main.tf .gitignore
git commit -m "initial: t3.micro + db.t3.medium"
git branch -M main
git remote add origin https://github.com/YOUR_USERNAME/infracost-demo.git
git push -u origin main

Step 5 — Add the GitHub Actions Workflow

mkdir -p .github/workflows
cat > .github/workflows/infracost.yml << 'EOF'
name: Infracost
on:
  pull_request:
    types: [opened, synchronize, closed]
jobs:
  infracost:
    name: Infracost diff
    runs-on: ubuntu-latest
    permissions:
      contents: read
      pull-requests: write
    steps:
      - name: Checkout PR branch
        uses: actions/checkout@v4
      - name: Setup Terraform
        uses: hashicorp/setup-terraform@v3
        with:
          terraform_wrapper: false
      - name: Terraform init
        run: terraform init
        env:
          AWS_ACCESS_KEY_ID: mock_access_key
          AWS_SECRET_ACCESS_KEY: mock_secret_key
      - name: Terraform plan
        run: |
          terraform plan -out=tfplan.binary
          terraform show -json tfplan.binary > plan.json
        env:
          AWS_ACCESS_KEY_ID: mock_access_key
          AWS_SECRET_ACCESS_KEY: mock_secret_key
      - name: Setup Infracost
        uses: infracost/actions/setup@v3
        with:
          api-key: ${{ secrets.INFRACOST_API_KEY }}
      - name: Infracost diff
        run: |
          infracost diff \
            --path=plan.json \
            --format=json \
            --out-file=/tmp/infracost.json
      - name: Post Infracost comment
        run: |
          infracost comment github \
            --path=/tmp/infracost.json \
            --repo=$GITHUB_REPOSITORY \
            --github-token=${{ github.token }} \
            --pull-request=${{ github.event.pull_request.number }} \
            --behavior=update
EOF
git add .github/
git commit -m "add infracost github actions workflow"
git push

Step 6 — Add Your API Key as a Repo Secret

This step lets GitHub Actions authenticate with Infracost Cloud. The API key connects your CI pipeline to your Infracost account so it can fetch pricing data and post cost comments on pull requests. Without it, the workflow can still run Terraform, but Infracost won’t be able to generate or publish cost estimates.

Get your key:

infracost configure get api_key

Then, in GitHub, go to your repo. Navigate through Settings → Secrets and variables → Actions → New repository secret.

Create this key-value pair:

  • Name: INFRACOST_API_KEY
  • Value: paste your key from the command above

You can close this window. You should see this output in the Terminal:

Your account has been authenticated. Run Infracost on your Terraform project by running:

  infracost breakdown --path=.

Step 7 — Open the Expensive PR

Now create a branch with the costly change:

git checkout -b expensive-infra

Edit main.tf — change the two instance sizes back to the large ones:

  • instance_type = "t3.xlarge"
  • instance_class = "db.r5.2xlarge"

Push and open a PR:

git add main.tf
git commit -m "scale up: t3.xlarge + db.r5.2xlarge"
git push -u origin expensive-infra

Go to GitHub and open a pull request from expensive-inframain. Within about 60 seconds, the Infracost bot posts its first comment.

Understanding the Pipeline and the PR Comments

You’ll notice the pipeline will fail. Open the GitHub Actions tab and check the logs — it shows exactly what went wrong and what you need to fix.

Error: Governance check failed:
Comment posted to GitHub
- finops policy check failed: EC2 - consider using Graviton instances
- finops policy check failed: RDS - consider using latest generation instances for r family instances
- guardrail check failed: Cost increased by $864, threshold was $250. Review the estimate to ensure it meets your expectations. If you are unsure what to do, check with your team lead.

FinOps Policy Violations

Infracost checks your resources against AWS Well-Architected Framework recommendations. For example, it will flag:

  • Using db.r5 when db.r7i (newer generation, same price or cheaper) is available
  • Using t3 when Graviton (t4g) instances offer better price/performance

You can fix these issues by modifying the main.tffile accordingly.

Guardrails and Cost Thresholds

The pipeline fails because of this:

❌ Significant cost increase: please review
Cost increased by $840, threshold was $250.
Review the estimate to ensure it meets your expectations.
If you are unsure what to do, check with your team lead.

The $250 threshold is the default guardrail that Infracost Cloud pre-configures on new accounts. You can change it at **dashboard.infracost.io → Governance → Guardrails**. In a real team , you’d tune this per repo — tighter for dev environments, more generous for production scaling repos. You can also switch from a flat dollar threshold to a percentage-based one, which works better when the baseline cost varies.

The key idea is simple: engineers see the financial impact of infrastructure changes during code review instead of after deployment.

Infracost bot comments on PR.

Infracost bot comments on PR.

Conclusion

In this article, you built a complete Terraform cost visibility workflow with Infracost and GitHub Actions. You learned how to estimate infrastructure costs before deployment, review cost diffs directly in pull requests, and add FinOps guardrails into your CI/CD pipeline.

For platform engineering and DevOps teams managing cloud infrastructure at scale, this creates a much faster feedback loop between engineering decisions and cloud spending.

All code from this article is available at my github repo.

Thanks for reading, and see you next time!

You might also like:

[embed]Terraform Random Provider: Automate Unique Naming with Kubernetes Examples Learn how to generate stable, unique identifiers with the Terraform Random provider, step-by-step.medium.com

[embed]The Ultimate Terraform CLI Cheat Sheet A Curated Terraform Commands List Organized by Topicmedium.com


메타데이터
post_id
4cccb4e0e270
slug
infracost-finops-terraform-cost-estimates-to-github-prs-4cccb4e0e270
url
https://medium.com/curious-devs-corner/infracost-finops-terraform-cost-estimates-to-github-prs-4cccb4e0e270
canonical_url
https://medium.com/curious-devs-corner/infracost-finops-terraform-cost-estimates-to-github-prs-4cccb4e0e270
author_url
https://medium.com/@kirshiyin
status
ok
fetched_at
2026-07-09 13:13:48