Documentation menu

DiffCost documentation

DiffCost shows the dollar cost of BigQuery SQL and dbt changes in your pull requests, priced per query run, and can block merges that make queries too expensive.

What DiffCost does#

DiffCost is a GitHub Action with an optional dashboard. On every pull request (PR) it:

  1. finds the SQL files or dbt models the PR changes;
  2. dry-runs the base version and the PR version of each one in your own BigQuery project (a dry run is free and returns bytes scanned, never rows);
  3. prices the difference per query run, and parses both versions to flag risky changes such as a removed partition filter;
  4. posts one comment on the PR with the result.

An excerpt of a comment:

πŸ’° DiffCost β€” BigQuery Cost Report (cost per run)

Query / Model Current This PR Scan Delta Cost Change
fct_daily_revenue $2.09 $9.66 +1.21 TiB +$7.57 (↑362%)
stg_orders $0.031 $0.031 0 B β€”
TOTAL $2.12 $9.69 +1.21 TiB +$7.57 (↑357%)

⚠️ This PR increases query costs by $7.57/run (+357%, β‰ˆ$227.10/mo at 30 runs/mo).

πŸ” Root cause analysis: πŸ”΄ fct_daily_revenue: Partition filter removed: order_date >= '2024-01-01'

The full comment also has a line for the largest single-query increase, the change in bytes scanned and, here, a High Scan Warning. Reading the PR comment shows a full report and every line it can contain.

With an API key, on any plan, the Action also sends its results to the dashboard (30 days of history on Free) and uses the dashboard's pricing settings. Once the DiffCost GitHub App is installed, every PR also gets a diffcost/cost-check commit status; on Free it always passes. Without the App, no status is posted, and the PR comment says the App isn't installed. On a paid plan (Starter, Team or Enterprise) or during the 14-day Team trial, DiffCost also:

  • evaluates your cost thresholds and posts a failing diffcost/cost-check status when a PR exceeds them, which blocks the merge when you make it a required check;
  • sends Slack alerts when a PR exceeds your cost policy;
  • charts cost trends and, on Team, cost per PR author.

Your SQL goes only to BigQuery, in your project. With an API key, the DiffCost service receives the repository name, PR number, commit SHA, the PR author (only with send_author: true), the .diffcost.yml thresholds and runs per month, whether the run came from a merge queue, and numbers: per-run costs and bytes (PR totals, and per query with no identifier) and counts of analyzed and unknown queries. It never receives SQL, table or model names, or file paths. See Security and data.

Requirements and limits#

  • GitHub Actions on a Linux runner with Docker. DiffCost is a Docker action; GitHub-hosted ubuntu-latest runners work.
  • BigQuery and a Google Cloud project where a service account can run dry-run jobs and read the tables your SQL uses.
  • Plain SQL files must run as written: each file must run as written in GoogleSQL, with qualified table names and no templating or query parameters. See What DiffCost can price.
  • dbt Core with dbt compile in the workflow; dbt Cloud isn't required.
  • One DiffCost run per PR. It covers one dbt project, or one set of plain SQL files. A second run on the same PR overwrites the first run's comment and status.
  • Paid features need a GitHub organization, not a personal account. Only its GitHub organization owners can create API keys, set dashboard thresholds and manage billing.
  • Merge queues need the workflow to run on merge_group too. DiffCost then posts diffcost/cost-check on the queue's commit, so the required check works with a queue. See Merge queues.

Features by plan#

Free Starter ($49/mo, 5 seats) Team ($149/mo, 20 seats)
PR comment with per-run cost (BigQuery dry run) βœ“ βœ“ βœ“
Structural risk flags (removed partition filters, SELECT *, new JOINs) βœ“ βœ“ βœ“
Merge blocking: org-wide threshold in the dashboard, or each repository's .diffcost.yml β€” βœ“ βœ“
Slack alerts β€” βœ“ βœ“
Dashboard comparison history (needs an API key) 30 days 12 months Unlimited
Cost trends chart β€” βœ“ βœ“
Per-repository thresholds in the dashboard β€” β€” βœ“
Cost attribution per PR author (needs send_author: true) β€” β€” βœ“

The Free plan needs no account and no API key. For more than 20 seats or an audit log, ask about Enterprise at support@diffcost.dev. Details: Plans and billing.

Set up DiffCost#

  1. Quickstart: add the Action to a repository and get your first cost report. This needs no DiffCost account.
  2. BigQuery access and keyless auth: switch to keyless access (recommended).
  3. dbt projects: if you use dbt, compile manifests and keep a baseline.
  4. Merge blocking: block merges that exceed your cost policy.

Do steps 1 to 3 on the Free plan first. Have a GitHub organization owner sign in to the dashboard when you're ready for step 4: the first owner sign-in starts the 14-day Team trial.

Find what you need#

I want to… Read
understand what DiffCost measures and how How DiffCost works
read a cost report, or a Cost unavailable row Reading the PR comment
choose and change cost limits, and get Slack alerts Thresholds and alerts
use the dashboard: history, trends, settings, team Using the dashboard
track costs, and check that DiffCost keeps enforcing Monitoring
update the Action, rotate keys, add repositories, offboard Maintenance and updates
fix an error in the comment or the log Troubleshooting
look up an input, an output or a .diffcost.yml key Configuration reference

Terms used in these docs#

  • Per run: every dollar figure is the cost of running a query once. The monthly figure ("β‰ˆ$X/mo") is a projection: per-run cost Γ— runs per month (30 unless you change it).
  • Worst single query: thresholds compare against the largest increase of any one query in the PR, not the PR's total.
  • Base commit: the commit the PR is compared against. DiffCost uses base_ref if you set it; otherwise, with the default checkout of GitHub's merge commit, the base-branch commit that merge commit was built on (the base branch's tip at the PR's latest push); otherwise the PR's base commit (pull_request.base.sha).
  • Base cost: the per-run cost of the base version of a query, shown in the comment's Current column.
  • Unknown cost: a query DiffCost couldn't price, for example because the dry run failed. The comment shows it as a Cost unavailable row or a "dry-run failed" row. DiffCost never counts it as $0, and it blocks the PR when a threshold applies.
  • Not costed (dbt only): a model whose PR dry run fails only because it reads objects the same PR creates. It counts as an unknown cost only when structural analysis also flags a risk on it, or can't run on a model that already exists.
  • Baseline manifest: for dbt, the manifest.json compiled from your main branch, which DiffCost compares the PR's manifest against.
  • Cost policy: the thresholds that apply to a repository. Each row under the dashboard's Merge-blocking thresholds is one threshold.
  • Verdict: DiffCost's conclusion about a PR: blocked, over the policy but not enforced, enforcement unconfirmed, or within the policy.
  • DiffCost service: the hosted part of DiffCost. With an API key, the Action sends it the numbers; it applies your thresholds and posts the diffcost/cost-check status.
  • DiffCost admin: a GitHub organization owner. Admins create API keys, set dashboard thresholds and manage billing. Other members can view.
  • Seat: a person who uses the dashboard. CI runs never need a seat.

Something missing or wrong? Email support@diffcost.dev.