Skip to content
ExponaBLOG
TERRAFORM, IAC & CLOUD AUTOMATION · DAY 052 / 100

Cost estimation with Infracost: best practices explained

See the cost of a change before applying.

Expona Admin6 min read

Cost estimation with Infracost: best practices explained

Cloud infrastructure costs climb quickly when changes go untested. You deploy a larger database, add NAT gateways, or spin up additional compute—and suddenly your monthly bill shifts by thousands. Cost estimation with Infracost: best practices explained puts visibility into those changes before they reach production, letting your team make informed decisions at code review time.

Infracost integrates directly into your Terraform workflow, parsing your plan files and generating cost breakdowns. Unlike spending months discovering overages in billing dashboards, you see impact immediately. We'll walk through how to read plan outputs, embed cost estimates in pull requests, enforce budget thresholds, and build habits that make cost awareness part of your everyday development.

How Infracost reads the plan and estimates monthly cost

Infracost works downstream from terraform plan. You generate your plan file, then pass it to Infracost's CLI, which parses the resource changes and cross-references them against pricing data. The output shows you exactly which resources cost what, broken down by resource type and region.

Here's the basic flow:

  1. Run terraform plan -out=tfplan to generate a binary plan file
  2. Convert the plan to JSON: terraform show -json tfplan > plan.json
  3. Feed it to Infracost: infracost breakdown --path plan.json
  4. View the cost breakdown in your terminal

A typical output looks like this:

hcl
Name                                        Monthly Qty  Unit                  Monthly Cost
aws_rds_cluster_instance.main               1            on-demand instances   $146.00
  ├─ Database instance (on-demand, db.r5.large)
  ├─ Storage                                1,000        GB                    $100.00
  └─ Backup storage                         500          GB                    $5.00
aws_nat_gateway.public                      2            NAT gateways         $64.00
aws_ebs_volume.data                         10           GB                    $1.00

TOTAL MONTHLY COST                                                             $211.00

The beauty here is specificity. You're not guessing—Infracost knows your instance type, region, storage tier, and data transfer assumptions. It shows you not just the headline cost but the components that drive it. If you're adding a second NAT gateway, you'll see exactly $32 added to the bill.

In practice, we recommend running this locally during development so you catch cost issues before committing. A simple Makefile target makes this frictionless:

hcl
.PHONY: cost
cost:
	terraform plan -out=tfplan
	terraform show -json tfplan > plan.json
	infracost breakdown --path plan.json --format table

By making cost review a single command, engineers naturally check it as part of their development loop—just like running tests.

Show cost differences in pull requests

Local checks are a good start, but pull request integration is where the real habit change happens. When every code review includes a cost delta, the team begins to internalize the financial impact of infrastructure decisions.

Infracost provides a GitHub Action that automatically posts a cost estimate as a PR comment. Here's a minimal workflow:

hcl
name: Infracost
on:
  pull_request:
    paths:
      - '**.tf'
      - 'terraform.tfvars'

env:
  TF_VERSION: 1.5.0
  INFRACOST_API_KEY: ${{ secrets.INFRACOST_API_KEY }}

jobs:
  infracost:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - uses: hashicorp/setup-terraform@v2
        with:
          terraform_version: ${{ env.TF_VERSION }}

      - name: Run Infracost
        run: |
          wget -O infracost https://github.com/infracostdev/infracost/releases/download/v0.10.29/infracost-linux-amd64
          chmod +x infracost
          
          terraform init
          terraform plan -out=tfplan.binary
          terraform show -json tfplan.binary > plan.json
          
          ./infracost breakdown --path plan.json \
            --format json > infracost.json
          
          ./infracost comment github \
            --path infracost.json \
            --github-token ${{ github.token }} \
            --pull-request ${{ github.event.pull_request.number }} \
            --behavior update

When a teammate opens a PR, the action runs silently in the background. Within seconds, a comment appears showing the cost delta:

Infracost estimate changed
Previous monthly cost: $892.50
New monthly cost: $1,156.00
Change: +$263.50 (+29.5%)

Added:
aws_rds_cluster_instance.replica: +$146.00

This transparency shifts the conversation. A reviewer can now ask: "Do we need a read replica in staging?" or "Can we start with a smaller instance and scale up?" The cost becomes part of the design discussion, not a bill shock later.

For teams using GitLab or Bitbucket, Infracost supports native integrations via CLI flags. Self-hosted solutions can use webhooks or CI outputs to push estimates to any platform.

Fail or warn when changes exceed thresholds

Cost awareness is good. Enforced cost guardrails are better. Infracost can fail builds or emit warnings when changes exceed budget thresholds, preventing costly mistakes from merging by default.

Define a policy file to specify acceptable cost deltas:

hcl
version: 1
policies:
  - name: deny_large_increases
    resource_type: '*'
    condition:
      estimated_monthly_cost_greater_than: 5000
    actions:
      - block
  - name: warn_on_growth
    resource_type: '*'
    condition:
      percent_increase_greater_than: 25
    actions:
      - warn

Then reference it in your CI:

hcl
./infracost breakdown --path plan.json \
  --format json > infracost.json

./infracost comment github \
  --path infracost.json \
  --policy-file policies.json \
  --exit-code on-failure \
  --github-token ${{ github.token }}

With --exit-code on-failure, the build fails if any policy is violated. A 30% cost increase in staging now blocks the PR until someone explicitly justifies it. This isn't about being rigid—it's about forcing a conscious choice.

We typically use a tiered approach:

  • Production: Block increases over 5% or over $500/month absolute
  • Staging: Warn on increases over 25%; block over $1000
  • Development: Warn only; let developers experiment

Adjust thresholds to match your org's risk tolerance and budget. The key is being consistent—if you set a rule, enforce it.

Engineers learn cost implications early

Repeating cost review in every PR creates habit. Within weeks, you'll notice engineers writing Terraform differently. They'll right-size instances before proposing them. They'll ask "Is this a t3 or r5?" instead of shrugging at the defaults. They'll question whether a feature really needs three availability zones or two.

This shift is cultural, not technical. When cost is invisible, engineers optimize for simplicity or feature completeness. When cost is visible and reviewable, optimization becomes natural. A developer sees that switching from db.r5.xlarge to db.r5.large saves $200/month, and suddenly they're reading Infracost output like they read test coverage reports.

Encourage this by making cost a review criterion. Update your code review checklist:

  • Does this change have a clear cost impact (checked via Infracost)?
  • Is there a cheaper alternative that meets the requirements?
  • Have you considered reserved instances or savings plans for production workloads?
  • If cost increased, is it justified by business requirements?

Share Infracost output in retros and postmortems. Celebrate cost optimizations. Over time, cost awareness becomes part of your engineering DNA, and your infrastructure naturally trends toward efficiency.

Common mistakes

  • Running Infracost against unchanged code: If you don't modify your Terraform, Infracost shows the current state, not the delta. Only run it after plan changes—that's where the insight lives.
  • Ignoring data transfer and miscellaneous charges: Infracost captures compute and storage well, but real-world bills often include data egress, cross-region replication, and API calls. Use it as a baseline, not gospel.
  • Setting thresholds too strict or too loose: A 1% threshold creates alert fatigue. A 100% threshold is useless. Calibrate based on your org's cost baseline and tolerance. Re-check quarterly.
  • Forgetting about reserved instances: Infracost calculates on-demand pricing by default. If you buy RIs or Savings Plans, the real cost is lower—document this separately so teams don't overestimate.
  • Not tying cost to business metrics: A $100 increase is meaningless without context. Is it for 10% more revenue? A small optimization? Couple Infracost data to business outcomes so cost discussions stay grounded.

Key takeaways

  • Infracost parses Terraform plans and cross-references pricing APIs to estimate monthly cost before deployment, giving you visibility during code review rather than in billing dashboards.
  • Integrate Infracost into your CI/CD as a GitHub Action (or equivalent) so cost deltas appear automatically on every PR, making cost a routine part of the review conversation.
  • Use policy files to enforce budget thresholds—block high-cost merges by default, but allow exceptions with explicit justification.
  • Consistent cost review gradually shifts engineer behavior toward efficient infrastructure choices, making cost optimization a habit rather than an afterthought.
  • Treat Infracost as a baseline tool, not the final word—layer in RI pricing, data transfer estimates, and business context to paint a complete picture.
ShareXLinkedInReddit

Found this useful? Support the writing.

Buy me a coffee
Written by
Expona Admin
Site administrator

Comments

Loading comments…

Leave a comment

Comments are reviewed before they appear. Be kind and stay on topic.

Related articles