Documentation menu

Using the dashboard

Sign in, read your organization's cost history, inspect a pull request's verdict, and manage thresholds, API keys, pricing, members and billing.

The dashboard at diffcost.dev shows the results that the Action sends with an API key, on any plan (30 days of history on Free). Without an API key the Action still works (pull request (PR) comment and job summary), but nothing reaches the dashboard.

Sign in#

Sign in with GitHub. The dashboard works for GitHub organizations, not personal accounts.

  • Several organizations: the first time you sign in, DiffCost asks which organization owns the repositories it will check. Nothing is preselected. Tags show which organization "already uses DiffCost" and where "you're an owner". You stay in that organization at later sign-ins.
  • Organization missing from the list: it probably restricts OAuth App access. A GitHub organization owner must approve DiffCost first (in GitHub, the organization's Settings → Third-party access → OAuth app policy); then sign in again.
  • Roles: GitHub organization owners are DiffCost admins, re-checked at every sign-in. Everyone else is a member with read access. There is no other way to become an admin.

To use DiffCost with another organization later, see Switch organization.

Who can do what#

Action Admin Member
View the overview, comparisons, trends and team pages ✓ ✓
Create, update and delete thresholds, and send Slack test messages ✓ —
Generate and revoke API keys ✓ —
Change BigQuery pricing settings ✓ —
Remove members (not yourself, and not the last admin) ✓ —
Subscribe, change or cancel the plan ✓ —
Switch to another organization ✓ (not the last admin of an organization with other members) ✓

Members see a "Read-only for members" tag on Settings, and "Ask an org admin to upgrade." on Billing. Installing the DiffCost GitHub App is a GitHub permission, not a DiffCost one: it usually takes a GitHub organization owner.

The sidebar has Overview, Team, Settings, Billing and Docs. At its foot are your organization, its effective plan (Free, Starter, Team or Enterprise), the Team trial state ("{N} days left", "not started" or "ended"; amber in the trial's last 3 days and once it has ended), your GitHub login and Sign out. On a phone, open the sidebar with the menu button.

Banners at the top of each page tell you when something needs an admin:

  • Trial not started: "Your 14-day Team trial starts when a GitHub owner of {org} signs in to DiffCost." Until then the organization is on the Free plan.
  • No admin yet: the organization has no DiffCost admin right now (for example, its only admin is no longer a GitHub organization owner), so nobody can create API keys, set thresholds or manage billing until a GitHub owner signs in.
  • Trial ended: "Your Team trial has ended. Upgrade to keep merge blocking and cost trends." Admins get an Upgrade button; members see "Ask an org admin to upgrade." The Billing page shows its own trial-ended section instead of this banner.
  • Over the seat limit (admins only): more members than the plan's seats, with Manage members and Manage plan buttons. See Members and seats.

After Stripe checkout, a banner says "Payment received…" (the plan switches once Stripe confirms it, usually within a minute) or "Checkout cancelled. You have not been charged."

Overview#

Last 30 days#

Four figures cover the last 30 days, each with its value for the 30 days before. Merge-queue runs aren't counted.

  • PRs analyzed: PRs DiffCost analyzed, each counted once.
  • Cost added: the sum of per-run cost increases, each PR counted once at its latest run, with the monthly projection below it.
  • Cost removed: the sum of per-run cost decreases, each PR counted once at its latest run, with the monthly projection below it.
  • PRs blocked: PRs that were over a threshold and got a failing diffcost/cost-check status, on any run in the window.

Everywhere in the dashboard, red means a cost went up and green means it went down.

Net cost change#

Available on Starter, Team and the trial. The chart plots the net per-run cost change across all repositories, each PR counted once at its latest run. Choose 7 days, 30 days, 90 days (the default) or 1 year; your plan's history caps the range. 7 and 30 days group by day, 90 days and 1 year by week (starting on Monday, UTC). Every day or week in the range has a bar, $0 when it had no PRs, so the time axis is even. Red bars are increases, green bars decreases. Hover a bar for its amount and number of PRs. Merge-queue runs aren't included.

On the Free plan an upgrade prompt replaces the chart.

Pull requests#

Every Action run is its own row (a comparison), newest first: a PR pushed four times has four rows. Runs that found no SQL changes are hidden. A run in a merge queue has a Merge queue badge: if its diffcost/cost-check status failed, that's the check that kept the PR from merging. The table only goes back as far as your plan's history: 30 days on Free, 12 months on Starter, unlimited on Team.

Column Shows
Pull request The PR number and repository.
Author The PR author's GitHub login, or "—" when send_author isn't true (in the workflow or in .diffcost.yml).
Cost per run The base branch's cost per run on a "−" line and the PR's on a "+" line. The "+" line is red when the cost went up and green when it went down. "—" when the cost is unknown.
Change Net per-run change, with "≈±$X/mo" below it, and how much more or less data the PR scans (PR bytes ÷ base bytes, for example "4.6× data scanned"; red above 2×).
Result "Blocked" (over a threshold, and the failing status was posted), "Over threshold, not enforced" (over a threshold, but no failing status was posted, so GitHub didn't block the merge), "Not checked" (no threshold applied, or merge blocking was off on the Free plan) or "Passed" (within the threshold that applied).
When How long ago the run reported ("2d ago"; older runs show the date). Hover for the time in UTC.

On a phone the table shows the pull request, its cost and the result, with the author and time under the PR number.

  • Search matches the repository or the author (part of the name is enough).
  • The result filter shows Over threshold (which includes "not enforced" rows) or Not over threshold (passed and not checked).
  • Filters are kept in the page URL, so you can bookmark or share a filtered view.
  • 25 rows per page.

Comparison details#

Click a row (or tab to its PR number and press Enter) to open its details. They describe the cost policy that applied when the run happened, not today's settings. The header shows the PR author (or "No author sent"), when the run reported (in UTC) and the short commit SHA. A merge-queue run also explains that the status went on the queue's commit and that queue runs aren't counted in the totals.

  • Result: "Blocked", "Over threshold, not enforced", "Not checked" or "Passed".
    • A blocked run lists the reasons, for example "Worst query +$7.57/run exceeds $5.00/run limit", "Worst query +362% exceeds 200% limit" or "2 queries could not be costed". The reasons give the limit, not which threshold it came from.
    • A passing run says which threshold it was within (repository, org-wide or .diffcost.yml) and its limits, that no threshold applied, or that merge blocking was off on the Free plan. (A Free-plan run without the DiffCost GitHub App says that no threshold applied.)
    • When some queries couldn't be costed: "{N} queries could not be costed and are excluded from the totals."
  • GitHub commit status: whether the diffcost/cost-check status was posted: "Posted", "Could not be posted", "GitHub App not installed for this repository", "Not configured on this server" or "Not posted (no commit SHA sent)".
  • Cost per run: base and PR cost per run as a diff, the net change and the monthly projection at the run's runs per month; then the largest single-query increase, the data scanned per run (base → PR, in the same units as the PR comment, with the multiplier) and the number of files analyzed.
  • Open pull request on GitHub opens the PR.

The details never include SQL, table names or file paths: the DiffCost service never receives them.

Settings#

Merge-blocking thresholds#

The badge at the top says whether DiffCost can enforce thresholds:

Badge Meaning
"GitHub App installed for all repositories" or "for selected repositories" DiffCost can post statuses. With selected repositories, check that every repository that runs DiffCost is included (manage repository access).
"Commit statuses enabled" DiffCost can post statuses, but couldn't tell which repositories the App covers.
Install the DiffCost GitHub App The App isn't installed on your organization. Click it to install.
"GitHub App not installed on this organization" The App isn't installed, and the page has no install link. Email support@diffcost.dev.
"Merge blocking not configured on this server" A problem on DiffCost's side. Email support@diffcost.dev.
"Merge blocking off on the Free plan" Free, a trial that hasn't started, a trial that ended, or a Stripe subscription that is unpaid or paused. Thresholds are kept but not enforced. Once the DiffCost GitHub App is installed, the status always passes; without it no status is posted. This badge has no install link: install the App from its GitHub page if you want the passing status.

The table lists each threshold: its repository ("All repositories *" or one repository), its limits ("+$X/run" and "+N%"), and its Slack alert ("Webhook set"; the dashboard never shows the URL again). On Starter and Free, per-repository rows (for example ones created during the trial) show "Inactive: needs Team".

When a threshold's last Slack alert failed, its row says "Last Slack alert failed {date}: {reason}. Check or replace the webhook URL." The message goes away when an alert or a test message succeeds, or you save a new webhook URL. Send test message (admins, on Starter, Team or the trial) posts a test message to the threshold's webhook and shows whether Slack accepted it; a failed test message is recorded like a failed alert. Slack alerts don't arrive explains Slack's answers.

To add a threshold (admins; Starter, Team and the trial), use Add or update a threshold:

  1. Repository: * for the org-wide threshold, or {org}/repo (Team plan). On Starter the field is fixed to *.
  2. Max increase per query ($/run): for example 5.00. 0 means any increase blocks.
  3. Max increase per query (%): a whole number from 1 to 100,000.
  4. Slack webhook URL (optional): an https://hooks.slack.com/… incoming webhook.
  5. Click Save threshold.

Set at least one limit. Each scope has one threshold. To change a threshold:

  1. In Repository, enter the threshold's scope. The button changes to Update threshold and the form fills in the current limits.
  2. Edit the limits. DiffCost removes any limit you leave blank.
  3. To replace the Slack webhook, enter a new URL. To remove it, tick Remove this policy's Slack webhook. Otherwise DiffCost keeps the current webhook.
  4. Click Update threshold.

To delete a threshold, click Delete in its row.

Changes apply from the next DiffCost run; DiffCost doesn't recompute existing statuses and comparisons. Thresholds and alerts explains how policies are evaluated.

GitHub Action API keys#

Each key shows its name, its prefix (the first 12 characters), the repositories it covers and Last used ("5m ago", or the date for older use; hover for the time in UTC; updated at most every 5 minutes; "Never used" for a new key).

Create a key (admins, any plan):

  1. Click Create API key.
  2. Name: for example "warehouse repository: DIFFCOST_API_KEY". Naming the key after the secret that stores it helps when you rotate keys.
  3. Repositories: * (every repository your organization owns) or a comma-separated list such as acme/warehouse, acme/marts. Repositories must belong to your organization.
  4. Click Create key, then Copy key. The key (cg_…) is shown once: DiffCost keeps only a hash, a check value and the first 12 characters, so it can't be shown again. Click Done when you've stored it.

Store it as the DIFFCOST_API_KEY Actions secret (and as a Dependabot secret). An organization can have up to 10 keys on Free and Starter, 40 on Team and the trial, and twice its seats on Enterprise. You can create 2 keys a minute.

To revoke a key, click Revoke in its row. Workflows that still use it keep posting PR comments but no longer get a diffcost/cost-check status, so if that check is required, their PRs can't merge until the workflow uses a new key. To replace a key without downtime, see Rotate an API key.

BigQuery pricing#

Admins set the organization's BigQuery billing model under Pricing model, then click Save pricing. With an API key, these settings override the Action's cost_per_tb and bq_pricing_model inputs and the bq_pricing_model key in .diffcost.yml:

  • On-demand ($ per TiB scanned): PR comments show dollars at the Cost per TiB rate (default $6.25; enter your negotiated rate if you have one).
  • Editions (slot-based): PR comments show bytes scanned and scan multipliers instead of dollars. DiffCost still prices each query at the Cost per TiB rate: dollar thresholds, the dashboard's figures and Slack alerts use that on-demand equivalent, so keep the rate set.

Runs per month for the "≈$X/mo" projection isn't a dashboard setting: set default_runs_per_month in each repository's .diffcost.yml.

Team#

Members and seats#

The Members and seats table lists everyone who has signed in: their role, when they joined, and whether they have a seat.

  • Seats go to members in the order they joined, up to the plan's seats (5 on Free and Starter, 20 on Team and the trial). Admins count toward the limit, and always keep access, even beyond it.
  • Members beyond the limit see an "over the seat limit" page until a seat frees up. PR comments and merge checks keep working meanwhile.
  • New people can't join while the organization is full. GitHub organization owners always can.
  • Leaving the GitHub organization doesn't free a seat: an admin removes the person here.

To free a seat, click Remove next to a member. Admins can't remove themselves or the last admin. A removed member who signs in again rejoins at the end of the seat queue, if a seat is free. A removed admin rejoins as an admin at their next sign-in, because they're still a GitHub organization owner: remove them as an owner on GitHub first to keep them out.

Switch organization#

Your organization → Switch organization lets you use DiffCost with another GitHub organization you belong to. You pick the organization on the next screen. You stay in the current one until you choose, and your seat there is freed once you do. If you come back later, you rejoin at the end of its seat queue. The last admin of an organization that has other members can't switch until another GitHub organization owner signs in, or the other members are removed.

If GitHub says you've left your organization, your next sign-in asks you to choose another one.

Cost attribution#

Available on Team and the trial. Cost by author lists PR authors over the last 30 days, using the latest run of each PR (merge-queue runs aren't counted), with the totals above it. Each row shows the author's PRs, the cost they added ("+$X", red), the cost they removed ("−$X", green), how many of their PRs were blocked, and the net change per run. Authors whose PRs lowered cost the most, net, come first.

Author logins are only sent when send_author is true, in the workflow or in .diffcost.yml. If PRs ran in the last 30 days but none has an author, the table says "Author names are off" (with no PRs at all, "No pull requests in the last 30 days"). Otherwise PRs without an author are left out.

Billing#

The Billing page shows your plan, trial days left, seats used and how you're billed, and lets admins subscribe, change or cancel. See Plans and billing.

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