Skip to main content

whatbreaks

Know what a dbt change breaks — before you merge it.

Column-level blast radius in CI. No warehouse, no secrets, no backend.

CI Python License Status


whatbreaks detecting a breaking dbt change

Real CLI output. CI regenerates this image and fails if it has drifted.


The problem

You remove a column. dbt build passes. Three hops downstream a dashboard breaks, and you find out a week later from an angry Slack message.

dbt ls --select model+ knows which models are downstream. It does not know which columns are — so a change to one column flags every model beneath it, whether or not that column reaches them. Technically correct, too coarse to act on.

Model-level versus column-level blast radius

Both models are downstream. Only one selects the column — the other breaks because it filters on it, which never shows up in the output schema at all. whatbreaks reports both, and says which is which.

Why not the existing tools

Column-level lineage for dbt is not new. sqlglot does the parsing and several good tools build on it. The gap is that every existing CI impact tool needs infrastructure:

Tool Requires
Recce live warehouse + two dbt environments
dbt-column-lineage catalog.json, i.e. a warehouse
SQLMesh adopting SQLMesh as your framework
dbt Cloud Explorer dbt Cloud, Enterprise tier
Datafold · Atlan · Sifflet · Metaplane a hosted catalog (SaaS)
whatbreaks dbt parse output. Nothing else.

Because it needs no credentials, it can run on pull requests from forks — where GITHUB_TOKEN is read-only and secrets are withheld.

If you already run Recce or Datafold, they answer a different and often better question — "did the data actually change?" — by querying your warehouse. whatbreaks answers "what could break?" statically, in seconds, for free.

Try it

The repo ships a runnable example. No warehouse, no dbt install:

git clone https://github.com/Ridadata/whatbreaks && cd whatbreaks
pip install -e .

whatbreaks check \
  --base examples/quickstart/base/target/manifest.json \
  --head examples/quickstart/head/target/manifest.json

That is the run in the demo above. See examples/quickstart for what it models.

Four runtime dependencies. No warehouse driver, no service, no account.

Use it on your project

You need two manifests — one from the base commit, one from your change. dbt parse produces them offline, with no warehouse connection:

git worktree add ../base origin/main
(cd ../base && dbt parse)     # base
dbt parse                     # your change

whatbreaks check --base ../base/target/manifest.json --head target/manifest.json
Flag
--fail-on breaking default — only confirmed breakage fails the run
--fail-on possibly-breaking stricter
--fail-on never report only, always exit 0
--format text | json | markdown humans · tooling · PR comments

Exit codes0 clean · 1 findings at or above the threshold · 2 bad input (nothing analysed).

Not on PyPI yet. The release is prepared but unpublished. This note disappears the moment pip install whatbreaks works.

Measured, not asserted

Across 7 public dbt projects (164 models), with no warehouse:

75.6% of models resolve their output columns exactly method →
83.5% have a usable schema
93.3% on analytics-style projects, the target population
0 false positives on the no-op corpus 15 cases →
11.5s to analyse a 500-model project, cold

The 93.3% rests on 2 projects and 15 models — directionally right and under-evidenced. The package subset (73.8%, a harder population) is the conservative floor. Full method and threats to validity are in ADR 000; the scripts in tools/ reproduce every number here.

What it reports

Rule Change Severity
WB001 column removed breaking · possibly · safe, by blast radius
WB002 model removed breaking if still referenced
WB003 column added safe
WB900 model could not be analysed info

Renames, type changes and expression changes are inference rather than fact. They wait for later releases instead of shipping as guesses.

How it works

Two manifest.json files in, findings out — no warehouse, no network:

recover SQLinfer output columnsbuild column lineagediff the two graphs

The last step is the one that matters: it is a graph diff, not a text diff. Reformatting and CTE renames produce nothing, and a model whose columns changed because an upstream SELECT * changed is caught even though its own file was never touched.

Full walkthrough →

Honesty by design

  • Never overclaim. Every finding carries a severity and an independent confidence. Coverage is always reported, so a clean result is never mistaken for a complete one.
  • Absence of evidence is not evidence of absence. A removed column with no consumer is safe only when coverage is complete — otherwise possibly_breaking.
  • Deterministic. No network calls, ever — enforced by a test that blocks sockets. No LLMs.

Limitations

Explicit by design, not apology. Full list in docs/limitations.md.

  • Without catalog.json, SELECT * over a source with no declared columns cannot be expanded. Reported partial, never guessed. (A star over a CTE resolves fine — most do.)
  • Macros needing a live warehouse (run_query, adapter.get_relation) are unresolvable offline and say so by name.
  • Python models are out of scope, and are named as such rather than reported as a parse error.
  • whatbreaks reasons about schema, not values. Whether your numbers changed is a different question, and Recce and Datafold answer it well.

Status

v0.1.0 — early, but real. Tested against real dbt projects and honest about what it could not analyse. Not yet here: the GitHub Action, rename and type-change detection, suppressions. The JSON output carries its own schema_version so tooling can pin while the shape settles.

Contributing

Found SQL whatbreaks gets wrong? A corpus case is the most useful possible bug report — one YAML file, no code. It reproduces the problem, documents the expectation, and becomes the regression test the moment it is fixed.

A break we failed to report is the more valuable half: false negatives mean someone merges a breaking change believing it is safe. See CONTRIBUTING.md.


MIT licensed · Changelog · Limitations · Security

Download files

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

Source Distribution

whatbreaks-0.1.0.tar.gz (144.7 kB view details)

Uploaded Source

Built Distribution

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

whatbreaks-0.1.0-py3-none-any.whl (62.2 kB view details)

Uploaded Python 3

File details

Details for the file whatbreaks-0.1.0.tar.gz.

File metadata

  • Download URL: whatbreaks-0.1.0.tar.gz
  • Upload date:
  • Size: 144.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for whatbreaks-0.1.0.tar.gz
Algorithm Hash digest
SHA256 392ed2d17e9a2186bbcd673a934abc85e6b54d93faa16ef4463ff9671447ad19
MD5 534bbd5cb0c2a7f9d44789159bdd26aa
BLAKE2b-256 34dd3a38cf5da458b60bc32ed4a6a838e62946810a4ec1a4a6f952a9e276d1ca

See more details on using hashes here.

Provenance

The following attestation bundles were made for whatbreaks-0.1.0.tar.gz:

Publisher: release.yml on Ridadata/whatbreaks

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

File details

Details for the file whatbreaks-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: whatbreaks-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 62.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for whatbreaks-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 a84a48f686e603735c9779d700a699bf0f2be626fc40dd805cae1ecb7c4fbe44
MD5 f5e9b6a6eb8e90e24aa19ae23c3131cf
BLAKE2b-256 5f68b9049c271ce79b51de4e9260b07084f586e9652be47886fd3d0dec746f70

See more details on using hashes here.

Provenance

The following attestation bundles were made for whatbreaks-0.1.0-py3-none-any.whl:

Publisher: release.yml on Ridadata/whatbreaks

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 Sentry Error logging StatusPage Status page