Cloud cost estimation for Terraform and CloudFormation. Open source, no API key, no SaaS, no telemetry phone-home. Pulls live prices from pricing.c3x.dev and caches them locally.
$ c3x estimate
── c3x estimate · USD ─────────────────────────────────────────
aws_instance.web
Instance usage (Linux/UNIX, on-demand)
730 hours × $0.192 = $140.16/mo
aws_instance.web subtotal: $140.16/mo
aws_db_instance.primary
Database instance
730 hours × $0.068 = $49.64/mo
Storage
50 GB-month × $0.115 = $5.75/mo
aws_db_instance.primary subtotal: $55.39/mo
──────────────────────────────────────────────────────────
PROJECT TOTAL: $195.55/mo
# Homebrew (macOS)
brew install c3xdev/tap/c3x
# Install script — detects your OS/arch, verifies the checksum
curl -fsSL https://c3x.dev/install.sh | sh
# Docker
docker pull ghcr.io/c3xdev/c3x
# From source
go install github.com/c3xdev/c3x/cmd/c3x@latestPre-built binaries and checksums for every release are on the releases page.
# Cost estimate of the current directory's Terraform config.
c3x estimate
# Run against a specific path; emit JSON for machine consumption.
c3x estimate --path infra/ --format json | jq .project_total
# Markdown for a PR comment.
c3x estimate --format markdown > pr-comment.md
# Override a variable.
c3x estimate --var 'env="prod"' --var-file=overrides.tfvars
# Run offline (no calls to pricing.c3x.dev; uses the offline stub).
c3x estimate --offline
# Inspect the on-disk price cache.
c3x pricing where
c3x pricing stats
c3x pricing clearc3x reads from five layers, in increasing priority:
- Built-in defaults
- User config:
~/.config/c3x/config.toml - Project config:
./.c3x.toml - Environment variables prefixed
C3X_ - CLI flags
Project config example (.c3x.toml):
region = "us-east-1"
format = "markdown"
budget = 1000.0
[pricing]
endpoint = "https://pricing.c3x.dev/graphql"cmd/c3x/ # CLI entry (cobra + viper)
cmd/verify_catalog/ # Catalog health harness
internal/
├── domain/ # Core types — Resource, Cost, Estimate, Diff
├── config/ # 5-layer configuration resolution
├── observability/ # slog + OpenTelemetry tracer
├── catalog/ # Embedded TOML resource definitions + Registry
├── expr/ # Expression evaluator (expr-lang/expr wrapped)
├── parser/ # IaC parser dispatcher
│ ├── terraform/ # HCL parsing (hashicorp/hcl/v2)
│ └── plan/ # Terraform plan JSON
├── pricing/ # HTTPSource → DiskCache → MemoCache chain
├── calculator/ # Orchestrator
└── render/ # text / markdown / json renderers
resources/ # Embedded TOML catalog snapshot — the
# offline fallback shipped inside the binary
testdata/corpus/ # Real-world Terraform configurations used
# by integration tests
Module dependencies flow inward toward domain. The depguard
linter enforces the dependency rules in CI; an import that crosses
the wrong boundary fails the lint job before review.
| Workload | Time |
|---|---|
| Parse a 500-resource monorepo (vars + locals + count + for_each + modules) | 10ms (Apple M3 Pro) |
| Cold estimate against pricing.c3x.dev | 3-5 seconds (network-bound) |
| Warm estimate (SQLite cache hit) | 35ms |
Numbers from internal/parser/terraform/bench_test.go; CI runs the
benchmark on every push so regressions fail the build.
The catalog is the knowledge base served by pricing.c3x.dev. At
estimate time c3x loads it remote-first: the live /catalog bundle,
then the on-disk cache, then an embedded snapshot for fully-offline
use. Each kind is classified:
- live — every dimension prices via the upstream API and tracks vendor price changes automatically.
- static — inline-rate fallbacks for products the upstream doesn't expose cleanly; these don't track upstream changes.
- free — legitimately-free resources (e.g. public ACM certs, ALB target groups that bill via their parent).
- zero / errored — a hard CI failure if non-empty.
Run the verifier against the live API to regenerate the health report (see CATALOG_STATUS.md for current counts):
go run ./cmd/verify_catalogApache License 2.0 — see LICENSE.