Build Infracost Cloud

KINDAreplaces $1000/mosaves $12,000/yrback to the verdict

0%0 of 17 items done

Saved on this device only. Tick prerequisites first, then work the phases in order · do not start one until the checks above it pass.

A cost estimation tool for infrastructure changes whose value depends entirely on being honest about coverage: the fixed costs are computable from the definitions, the usage-driven ones are not, and conflating them produces confident wrong numbers people act on.

estimated effort multi-daythe files for this build are in the project pack

ParsingInfrastructure definitions parsed to a resource graph, provider-specificPricingA dated price catalogue per provider and regionCoverageExplicit per-resource support state, with unsupported ones countedUsageDeclared assumptions for usage-driven costs, never inferredReportingDiffs against a baseline, in a pull request comment

Before step 1

Everything below is assumed from the first step. Tick each one when you actually have it, not when you plan to.

  1. installfree

    Why Runs the parser, the pricing layer and the reporting.

    Get it nodejs.org, or nvm install 22. open ↗

    Verify node --version prints v22 or higher

  2. installfree

    Why Parsing the source text is far less reliable than parsing a resolved plan, and the plan format is what resolves variables and counts.

    Get it The tool itself, plus a repository whose plan you can generate.

    Verify A plan output is generated and parsed into concrete resources

  3. free to read

    Why Prices vary by region and change, and hard-coding a sample produces estimates that drift without breaking.

    Get it The provider's own pricing interface, and record the date you fetched.

    Verify Prices for one resource kind differ correctly between two regions

  4. have readyfree

    Why Modules, variables and counts are where resolution actually fails, and a single-file example exercises none of it.

    Get it A repository with modules, variables and at least one resource whose cost is dominated by usage.

    Verify The repository parses with at least one unresolved and one usage-driven resource

  5. have readyfree if you own the infrastructure

    Why The honesty of the coverage reporting is only assessable by comparing an estimate against what was actually charged.

    Get it A recent bill for the environment your repository describes, broken down by service.

    Verify The estimate and the bill are compared and the gap is explained by the stated coverage

Data model

Create these before the first phase that stores anything. Changing a table later is the expensive kind of change.

- runs(id, repository, commit_sha, base_sha, ran_at, definitions_hash)
- resources(run_id, address, kind, region, attributes_json, support_state) · support_state is priced, usage_driven or unsupported
- prices(provider, region, sku, unit, amount_minor, currency, effective_from, fetched_at)
- estimates(run_id, resource_address, fixed_minor, usage_minor, usage_assumptions_json)
- usage_profiles(id, name, assumptions_json, source) · source is declared or default, never inferred
- diffs(run_id, base_run_id, resource_address, change_kind, delta_minor, coverage_changed)
- An estimate stores fixed and usage-driven components separately, so a total is never reported without saying how much of the cost is not in it.

Environment variables

These go in a .env file the app reads at startup. The pack's .env.example is this table as a file · copy it, never commit the filled-in version.

VariableNeededExampleWhere the value comes from
PRICE_CACHE_PATHrequired./cache/prices.jsonDated per fetch. A stale catalogue refuses to run silently.
PRICE_MAX_AGE_DAYSrequired14Beyond this an estimate requires an explicit acknowledgement.
USAGE_PROFILE_PATHrequired./infracost-usage.ymlDeclared usage. Absent means usage-driven resources report no figure.
INFER_USAGErequiredneverPresent as a constant. Inferred egress is a number with no basis.
REPORT_COVERAGErequiredalwaysPresent as a constant. A total without coverage is not interpretable.
DEFAULT_REGIONrequiredeu-west-1Used only where a resource does not state one, and reported when it is.

The build, in order

  1. Resolving what the definitions actually create

    A plan resolves to concrete resources with their shapes.

    1. A defaulted size is an estimate for infrastructure nobody is deploying.

      Files src/parse.ts

    2. Where the resource count actually comes from.

      Files src/expand.ts

    3. Alongside the total, not in a log.

      Files src/report.ts

    done when · tick each as it passes
    watch out
    • Assuming a default size for a resource whose shape depends on an unresolved variable produces an estimate for infrastructure nobody is deploying, and it looks identical to a correct one. Report unresolved shapes as unresolved and exclude them from the total rather than guessing.
  2. Prices with a date on them

    Every price used is dated and its staleness is visible.

    1. A stale catalogue is a wrong estimate that looks entirely normal.

      Files src/prices.ts

    2. The same resource differs substantially between regions.

      Files src/prices.ts

    3. Treating an absent price as zero understates the total silently.

      Files src/estimate.ts

    done when · tick each as it passes
    watch out
    • A price catalogue cached indefinitely produces estimates that drift from reality without anything appearing to break, and the first sign is a bill that does not match a report from six months ago. Date the catalogue, show its age, and refuse to run silently on a stale one.
  3. Saying what is not in the number

    Every estimate states its coverage explicitly.

    1. Priced, usage-driven, unsupported. Three states, all reported.

      Files src/coverage.ts

    2. Not in a footnote. It is what makes the total interpretable.

      Files src/report.ts

    3. By cost is impossible, since the excluded cost is what you do not know.

      Files src/coverage.ts

    done when · tick each as it passes
    watch out
    • Skipping resources the tool does not support, and reporting the total of the rest, produces a number that is confidently too low, and the resources most likely to be unsupported are often the expensive new ones. Count them, name them, and put the count where the total is.
  4. Usage assumptions, declared rather than guessed

    Usage-driven costs appear only where someone stated the usage.

    1. In the repository, reviewable alongside the change.

      Files src/usage.ts

    2. So a wrong number is traceable to a wrong assumption.

      Files src/report.ts

    3. Egress from instance size is a number with no basis.

      Files tests/no-inference.test.ts

    done when · tick each as it passes
    watch out
    • Inferring egress volume from an instance size produces a number with no basis that will nonetheless be quoted in a decision, and data transfer is precisely where estimates go most badly wrong. Require a declared profile, and where none exists report the resource as usage-driven with no figure rather than estimating one.
what this build does not replace
after v1, if you want it

Need the files? The project pack on the verdict page hands your agent the whole brief · more dev tools.