Skip to main content
dbt-costgate logo

dbt-costgate

The BigQuery cost gate for dbt pull requests.

Dry-run what changed, price the diff, and catch the $500-a-day model
before it merges — not on next month's bill.

CI PLE Python License Code style: ruff Status

Quick start · How it works · What you get · Where it fits · Pricing accuracy · Security · Roadmap · Contributing

New here? Start with dbt-costgate, explained — plain English, ten minutes, no prior context assumed.

[!NOTE] Working MVP. dbt-costgate check and the GitHub Action are implemented and tested. Every report shown here is generated from the real renderers by scripts/gen_samples.py, and CI fails if any of them drifts from what the code actually produces — the figures are illustrative, the output is not. See the usage guide and changelog.


The problem

On dbt + BigQuery teams, SQL changes merge with zero visibility into their cost impact. A changed join, a dropped partition filter, or a widened incremental window can multiply a model's bytes scanned — and the team finds out days later on the bill, or when finance escalates.

BigQuery's dry-run API returns the exact bytes a query would scan — for free, before running anything. dbt-costgate packages that into a first-class PR gate:

How dbt-costgate works: pull request → compile both versions → BigQuery dry-run → price the diff → gate

What you get on every PR

A sticky comment on the pull request, updated in place on every push. This is the comment itself — GitHub renders it from the same markdown dbt-costgate produces:

💸 dbt-costgate — cost impact of this change (2 models)

Model Baseline This change Δ % Δ / run Δ / month
fct_orders_daily full-refresh 819.20 GiB 2.91 TiB +264% USD +13.19 USD +395.63
dim_customers new 412.50 MiB USD +0.00 USD +0.07

fct_orders_daily — incremental — figure is the full-refresh scan

Net increase: USD 13.19/run · USD 395.70/month

Gate: FAIL

  • fct_orders_daily: USD +13.19/run exceeds USD 5.00
  • fct_orders_daily: +264% exceeds 25%

Pricing: US USD 6.25/TiB · built-in table (table 2026.07, verified 2026-07-25)
Estimates from BigQuery dry-run — nothing executed, no bytes billed, no SQL shown.

💻 The same check, in your terminal (real output)
dbt-costgate check --baseline path/to/main/manifest.json
dbt-costgate — region: US · on-demand USD 6.25/TiB · built-in table

  fct_orders_daily  (full-refresh): 819.20 GiB → 2.91 TiB   +264%   USD +13.19/run   USD +395.63/month (30 runs)
      ⚠ incremental — figure is the full-refresh scan
  dim_customers  (new): — → 412.50 MiB   —   USD +0.00/run   USD +0.07/month (30 runs)

  Net increase: USD 13.19/run · USD 395.70/month

  GATE: FAIL
    - fct_orders_daily: USD +13.19/run exceeds USD 5.00
    - fct_orders_daily: +264% exceeds 25%

  Pricing: US USD 6.25/TiB · built-in table (table 2026.07, verified 2026-07-25)
  Estimates from BigQuery dry-run — nothing executed, no bytes billed, no SQL shown.

Or run it with no baseline at all for an instant local read of what your changed models scan — and fail the run there on an absolute --max-usd-total / --max-tib-total ceiling (no baseline required) — or get the full before/after locally in one command with dbt-costgate check --against main (dbt-costgate compiles main for you in a throwaway worktree). See the usage guide.

Quick start

pip install dbt-costgate
gcloud auth application-default login

dbt compile
dbt-costgate check

That's the entire local setup — no baseline, no CI, no config file. Add a baseline and thresholds when you want it to block a PR; see the usage guide.

Every release also ships a wheel, an sdist, and SHA256SUMS if you'd rather pin to an artifact.

Documentation

So you know where to look before you open anything:

Document What's inside Go here when
Explained Plain-English guide: how it works, what it costs to run, which pricing setup you're in, every config key, the deliberate non-goals, and when a number can be wrong You're new, or you want to know what a setting does
Usage guide The how-to: install, CI setup, baselines, thresholds, the GitHub Action, worked examples for on-demand / negotiated / slot pricing You're setting it up or changing how it runs
Architecture Why it's built this way, the invariants, the hard edges You're contributing or reviewing a change
Security Threat model, and what counts as a vulnerability You're reviewing it for use next to production credentials
Changelog What changed in each release, in operator terms You're upgrading

Every example report in these docs is generated from the real renderers, and CI fails if one drifts — so what you read is what the tool actually prints.

How it works

Step What happens Cost to you
1 · Find what changed dbt's state:modified selector against a baseline manifest (your production artifacts), with a git-diff fallback free
2 · Compile both versions The baseline and PR-branch versions of each changed model free
3 · Dry-run each BigQuery dryRun=true returns exact bytes scanned — executes nothing, reads no table data free
4 · Price the diff Region-aware on-demand rates; optionally × run frequency for $/month free
5 · Gate Markdown PR comment, machine-readable JSON, policy-driven exit code (fail on a $ and/or % increase, or an absolute $/run or TiB/run ceiling) free

Where it fits

dbt-costgate is the preventive half of BigQuery cost control — it deliberately does not compete with the excellent retrospective tools:

The question you're asking Reach for
"What did our warehouse cost, by model / user / query?" dbt-bigquery-monitoring
"What does the dbt platform estimate my models cost?" dbt Cost Insights
"What is this PR about to do to our bill?" dbt-costgate

Accurate, transparent pricing

BigQuery on-demand rates differ by region — a gate that prices every byte at the US rate is silently wrong for half the world. dbt-costgate treats pricing accuracy as a feature:

  • 🌍 Versioned per-region pricing table with a last_verified date, auto-selected from your job's detected region.

  • 🧾 Every report discloses its math — region, rate, and rate source. Never a silent assumption:

    region: US (multi-region) · on-demand USD 6.25/TiB · source: built-in table 2026.07
    
  • ⚙️ Overridablepricing.region to force a region, pricing.usd_per_tib for negotiated or editions rates, pricing.currency to label amounts in your own currency (an ISO 4217 code — dbt-costgate labels, it never converts).

  • ⚠️ Honest limits, stated up front — under capacity/editions pricing, bytes scanned is a proxy signal, not your invoice; set a rate of 0 and reports drop money entirely and measure bytes instead. The 1 TiB/month free tier is not modeled by default.

Security model

This tool runs in CI next to warehouse credentials, so the design is deliberately boring:

Threat Design answer
Billable or data-reading queries Dry-run only. The single warehouse interaction is jobs.insert with dryRun=true — free, executes nothing
Credential theft / mishandling No credential surface. Auth delegates entirely to Application Default Credentials; in CI the documented path is keyless Workload Identity Federation. There are no credential flags to misuse
Compromised CI runner Least privilege. BigQuery Job User + metadata read — no data access, no writes; docs ship the exact IAM setup
Malicious fork PRs Fork-safe by default. Documented workflows use the pull_request trigger; fork PRs degrade to "no report", never to exposed secrets
Secrets templated into SQL No compiled SQL in reports — model names, bytes, and dollars only; snippets are strictly opt-in
Phone-home No telemetry. The only network call is to the BigQuery API

Details in SECURITY.md · deeper design notes in docs/architecture.md.

Roadmap

  • dbt-costgate check — local (zero-setup) + CI diff, region-aware pricing, threshold gating
  • One-command local diffdbt-costgate check --against main (isolated git worktree)
  • GitHub Action wrapper with a sticky PR comment
  • Absolute cost ceilings — gate on total $/run or TiB/run, not just the increase (works without a baseline, so it gates local mode too)
  • Config- and macro-only change detection — catch a change that reaches a model without touching its .sql file
  • pre-commit hook entry
  • Docker image on ghcr.io (GitLab CI–friendly)

Non-goals

  • Not a monitoring tool — retrospective observability belongs to dbt-bigquery-monitoring.
  • BigQuery first — one warehouse done accurately beats three done approximately. Other warehouses come only once BigQuery is genuinely finished, and only where the cost model actually transfers.
  • Never runs billable queries — features that require executing real queries are out of scope by design.
  • No IDE/editor integration (for now).

Explained · Usage guide · Contributing · Security policy · Changelog · Code of Conduct · Apache-2.0 · NOTICE

Built by Dashan Richards — DCO sign-off required, hard invariants apply:
dry-run only · no credential handling · no telemetry

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

dbt_costgate-0.8.0.tar.gz (112.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

dbt_costgate-0.8.0-py3-none-any.whl (49.4 kB view details)

Uploaded Python 3

File details

Details for the file dbt_costgate-0.8.0.tar.gz.

File metadata

  • Download URL: dbt_costgate-0.8.0.tar.gz
  • Upload date:
  • Size: 112.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for dbt_costgate-0.8.0.tar.gz
Algorithm Hash digest
SHA256 19c270acb1e8d6ea3bcea60eec0d8d23e923cf38e48f9117de5427177dd9760a
MD5 642a613716d8bb9caeb26c4990c00b85
BLAKE2b-256 275a4ba30f5bf2aee8e846b74dce30248d590930ecc017cd32c4b72c75414413

See more details on using hashes here.

Provenance

The following attestation bundles were made for dbt_costgate-0.8.0.tar.gz:

Publisher: release.yml on Drichards124/dbt-costgate

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file dbt_costgate-0.8.0-py3-none-any.whl.

File metadata

  • Download URL: dbt_costgate-0.8.0-py3-none-any.whl
  • Upload date:
  • Size: 49.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for dbt_costgate-0.8.0-py3-none-any.whl
Algorithm Hash digest
SHA256 2ec3544db988622d20f729c9002de2446b15e0100dfd864432ca6785696d7e6c
MD5 80ae2918d91bb71a898d0435c045ba79
BLAKE2b-256 16b488e40e59b457c8785dd1f3f890aaea779d72f1e9842a81380f5e20df4501

See more details on using hashes here.

Provenance

The following attestation bundles were made for dbt_costgate-0.8.0-py3-none-any.whl:

Publisher: release.yml on Drichards124/dbt-costgate

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page