Terraform

Cost Estimation with Terraform in Practice: An Infracost Playbook

2026-04-19
NicheeLab Editorial Team

If you eyeball pricing without ever looking at the code, you tend to discover surprisingly large gaps right before release. The safe pattern is to treat Terraform's plan output as your single source of truth and let Infracost evaluate the diff for you automatically.

This guide is grounded in Terraform's stable, official behaviour (the plan/show workflow) and organises Infracost so you can use it confidently in both real work and exam scenarios.

The Terraform Plan to Cost Estimate Flow

Cost estimates improve when you base them on a plan where variables, modules, and data sources are already resolved to concrete values, rather than reading HCL statically. In Terraform you generate a plan with terraform plan, then convert it to machine-readable JSON with terraform show -json. Handing that JSON to Infracost is the standard production pattern.

Treating the plan as your source of truth means conditional branches (count/for_each), default values, and provider resolutions are all baked in. You see the diff before apply and review it in the PR, so cost regressions get caught early.

  • Create the plan: terraform plan -out plan.out
  • Convert to JSON: terraform show -json plan.out > plan.json
  • Estimate: infracost breakdown --path plan.json
  • Diff: infracost diff (compare against the base and surface in the PR)
Aspectterraform planterraform applyInfracost
InputHCL + variables + state (read-only)Plan + external API callsplan.json or HCL/state
PurposeCompute the proposed changesApply the actual changesCalculate / compare cost
Outputplan.out / plan.jsonReal resource changes and state updatesCost breakdown and diff (JSON, table, PR comment)
Exam takeawayUnknown values get resolved by the planCost estimation does not require applyPassing plan.json improves accuracy

Data flow from plan to Infracost

Dev
  |
  v
terraform plan  ---->  plan.out  -- terraform show -json -->  plan.json
                                                          |
                                                          v
                                                  Infracost breakdown
                                                          |
                                                          v
                                                    コスト明細/PRコメント

Minimal local workflow

terraform init
terraform plan -out plan.out
terraform show -json plan.out > plan.json
INFRACOST_API_KEY=xxxxxxxx infracost breakdown --path plan.json

Setting Up Infracost with Terraform

Infracost is a CLI that calculates estimates by consulting each cloud provider's public price list. It can read HCL straight from a Terraform project directory, but for accuracy and reproducibility we recommend going through plan.json.

Integration is straightforward: set the API key as an environment variable and run breakdown against plan.json. In CI it's common to reuse the existing plan artefact and post the result as a PR comment.

  • Prereqs: Terraform CLI works and cloud provider authentication lets plan succeed
  • API key: export the INFRACOST_API_KEY environment variable
  • Prefer plan.json over reading HCL directly (conditional branches and module expansion get reflected)
  • Multiple directories or modules can be declared in infracost.yml

Setup snippet

# APIキー設定(例)
export INFRACOST_API_KEY=xxxxxxxxxxxxxxxx

# 計画の作成とJSON化
terraform plan -out plan.out
terraform show -json plan.out > plan.json

# 見積もり
infracost breakdown --path plan.json --format table

# 複数パスをまとめる infracost.yml(任意)
# version: 0.1
# projects:
#   - path: ./app
#   - path: ./infra/network

Practical Tips to Improve Estimate Accuracy

Usage-based pricing (storage GB-month, request counts, data transfer, etc.) can't be nailed down from HCL alone. Feeding Infracost realistic usage values via a usage file improves accuracy dramatically.

Pass production-equivalent variables via var-file so sizes and instance counts are concrete at plan time. If count/for_each conditions or default values are ambiguous, unknown values leak through and estimates swing.

  • Prepare a usage file (infracost-usage.yml) and spell out usage for your major services
  • Pin size and count with var-file. Use separate files per workspace/environment
  • Centralise price-affecting arguments like region, class, and disk type in locals
  • For parameters that depend on data source resolution, order them so they resolve during plan

Example usage file and var-file

# infracost-usage.yml(例)
version: 0.1
resource_usage:
  aws_s3_bucket.my_logs:
    monthly_tier_1_requests: 2000000
    storage_gb: 500
  aws_lb.app:
    new_connections: 10000000
    active_connections: 2000

# terraform.tfvars(本番)
instance_type = "t3.large"
volume_size   = 200
replicas      = 3

Wiring Into CI/CD and Gating Changes

The production playbook is to surface the cost diff in the PR and gate any change that crosses a threshold. Persist the base branch's estimate and compare it against the feature branch.

You can build this with the official GitHub Action or with plain shell. Tune failure conditions to your org policy by absolute amount or percentage increase.

  • Persist the base estimate (e.g. .infracost-base.json)
  • Generate the estimate on the change branch and compare with diff
  • Fail the job when the increase exceeds your percentage or amount threshold
  • Post a table-formatted comment on the PR so reviewers can decide immediately

GitHub Actions example (essentials only)

name: Cost Diff
on: pull_request
jobs:
  infracost:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Terraform Plan
        run: |
          terraform init
          terraform plan -out plan.out
          terraform show -json plan.out > plan.json
      - name: Setup Infracost
        uses: infracost/actions/setup@v2
      - name: Generate Base (main)
        if: github.event.pull_request.base.ref == 'main'
        run: |
          infracost breakdown --path plan.json --format json --out-file .infracost-base.json
      - name: Cost Diff
        env:
          INFRACOST_API_KEY: ${{ secrets.INFRACOST_API_KEY }}
        run: |
          infracost breakdown --path plan.json --format json --out-file current.json
          infracost diff --path current.json --compare-to .infracost-base.json --format table
          # 例: しきい値チェック(単純化)
          infracost diff --path current.json --compare-to .infracost-base.json --format json --out-file diff.json
          python .github/scripts/fail_on_threshold.py diff.json 20 100 # 20%または100通貨単位超で失敗

Exam Prep Essentials (Pro-Level)

The Terraform exams care less about cost estimation itself than about the correctness and reproducibility of the plan that underpins it. The keys are: treat plan as your source of truth, minimise unknown values, and make variables and conditionals explicit.

Fundamentals like count/for_each, lifecycle, variable precedence, and reading plan output (distinguishing create/replace/destroy) translate directly into your accuracy when interpreting cost diffs.

  • Be able to explain the flow: generate plan.json, then hand it to external tooling
  • Designing var-file and locals to reduce unknown (plan-time undecided) values
  • count/for_each expansion drives the instance count, which drives cost directly
  • lifecycle.prevent_destroy and friends don't apply to cost estimation, but they do change the plan result
  • Data sources aren't directly billable, but understand that their results can affect things like size

Commands to produce plan.json (quick reference)

terraform plan -out plan.out
terraform show -json plan.out > plan.json
# これをInfracostに渡す
infracost breakdown --path plan.json

Common Pitfalls and Fixes

When variables differ across workspaces or environments, planning with unintended defaults skews the estimate. Always specify a production-equivalent var-file, even in CI.

Misresolved provider aliases or module paths cause plan failures or extra unknown values. Reconcile your providers and required_providers blocks and audit dependencies with graph/console.

  • Forgetting to switch workspace: be explicit with terraform workspace select
  • Missing var-file: always pass -var-file=prod.tfvars
  • Region mismatch: centralise provider region/zone settings in locals
  • Data fetch order: make the data to resource dependency explicit (e.g. depends_on)
  • Configs missing from the price list may be mapped to an equivalent class, so leave a note

Diagnostic commands

terraform providers
terraform graph | dot -Tsvg > graph.svg
terraform console
# planの検証
terraform plan -out plan.out && terraform show -json plan.out | jq '.planned_values.root_module.resources[] | .type, .name'

Sample: Cost Diff Across Multiple Environments

A classic case: the same module but with different sizes for dev and prod. Generate plan.json for each environment, run Infracost diff, and the increase/decrease rationale lands right in the PR.

Because you only swap the var-file against a single HCL codebase, this is easy to standardise as part of your review process.

  • Split dev/prod var-files and generate two plan.json files
  • Build an estimate JSON from each plan and compare them with diff
  • Comment the diff on the PR and gate by threshold

Sample configuration and comparison run

# main.tf(抜粋)
variable "instance_type" {}
variable "replicas" { type = number }
resource "aws_instance" "app" {
  count         = var.replicas
  ami           = data.aws_ami.ubuntu.id
  instance_type = var.instance_type
}

data "aws_ami" "ubuntu" {
  most_recent = true
  owners      = ["099720109477"]
  filter { name = "name" values = ["ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*"] }
}

# dev.tfvars
instance_type = "t3.micro"
replicas      = 1

# prod.tfvars
instance_type = "t3.large"
replicas      = 3

# 実行
terraform init
terraform plan -var-file=dev.tfvars -out dev.out && terraform show -json dev.out > dev.json
terraform plan -var-file=prod.tfvars -out prod.out && terraform show -json prod.out > prod.json

# 見積作成
infracost breakdown --path dev.json --format json --out-file dev.cost.json
infracost breakdown --path prod.json --format json --out-file prod.cost.json

# 差分
infracost diff --path prod.cost.json --compare-to dev.cost.json --format table

Check Your Understanding

Pro

問題 1

A team wants to review an accurate cost estimate and its diff during PR review. Which workflow most reproducibly yields an estimate that reflects how modules and variables resolve?

  1. Run terraform plan -out plan.out, then terraform show -json plan.out > plan.json, then infracost breakdown --path plan.json combined with infracost-usage.yml
  2. Point infracost directly at the source directory and estimate from the state after apply
  3. Run terraform refresh-only and pass only the state file to infracost
  4. Run terraform apply, then compute the diff with infracost

正解: A

Making plan.json (the JSON-serialised plan) your source of truth folds in module expansion and concrete variable values, giving you an accurate and reproducible estimate with no apply required. A usage file further sharpens accuracy. State alone, or workflows that require apply, don't meet the requirement.

Frequently Asked Questions

What's the difference between pointing Infracost at an HCL directory versus passing plan.json?

Reading HCL directly is static analysis, so conditional branches and data source resolution don't always carry through, and you end up with more unknown values. plan.json contains the values Terraform actually resolved, which boosts both reproducibility and accuracy of your estimate.

How do I specify usage-based pricing?

Use a usage file such as infracost-usage.yml to provide realistic values for things like storage capacity and request counts. That pins down the "depends on usage" line items and prevents under- or over-estimation.

Can I get an accurate estimate without running apply?

Yes. Generate plan.json from terraform plan and terraform show -json, then run Infracost against it. You can review the cost diff with no apply required. apply is not a prerequisite for cost estimation.

Check what you learned with practice questions

Practice with certification-focused question sets

無料で問題を解いてみる
Author

NicheeLab Editorial Team

NicheeLab editorial team focused on data engineering and cloud certification learning. Content is structured around practical study needs and official exam domains.


Related articles
Terraform

HCL Syntax: Terraform's Configuration Language (2026)

HCL2 fundamentals for Terraform — blocks, attributes, expres...

Terraform

Terraform Authoring & Operations Pro: Complete Guide (2026)

Tactics for the Terraform Pro exam — module authoring, works...

Terraform

Terraform Providers: Plugin Management Fundamentals (2026)

Provider mechanics — required_providers, versions, mirrors, ...

Terraform

Terraform Resource Blocks: Declarative Infra Units (2026)

Resource block fundamentals — addresses, references, common ...

Terraform

Terraform Data Sources: Read-Only External Data (2026)

Data source basics — declaration, refresh behavior, dependen...

Browse all Terraform articles (102)
© 2026 NicheeLab All rights reserved.