Skip to main content

dbt-refmerge

CI Coverage PyPI Python OpenSSF Scorecard

Finds duplicated import CTEs in your dbt models — two CTEs reading different columns from the same {{ ref(...) }} — proves the merged version returns identical rows on your warehouse, and rewrites the file. Anything it can't prove, it leaves alone.

Use it

pip install dbt-refmerge
cd your-dbt-project
dbt-refmerge scan

That's it. The dialect is detected automatically from your profiles.yml/manifest.json (override with --adapter postgres if needed). You'll get one line per opportunity:

models/marts/orders.sql:3: CTEs order_items, order_items_summary import model.shop.stg_order_items; run dbt-refmerge check to prove a merge

Each line is a lead: two CTEs over the same upstream model that may merge into one. Then, on a branch:

git checkout -b refmerge-cleanup
export DBT_REFMERGE_SCRATCH_SCHEMA=refmerge_scratch     # where verification views go
dbt-refmerge check                                      # proves each merge on your warehouse
dbt-refmerge fix models/marts/orders.sql --dry-run      # preview the rewrite
dbt-refmerge fix models/marts/orders.sql                # re-proves, then applies it
git diff                                                # review, test, open a PR

scan and check never touch your files. fix refuses to write unless the proof passes on current data (applied=false plus a reason means it's working, not broken).

To prove a merge, check builds the original and the merged model as two views in the scratch schema (dbt creates it if needed; it must not be a schema your models build into), compares their column types and their rows as multisets in a single query, then drops both views. All models in a check share one batch of dbt calls, so a large project costs about as many dbt invocations as a small one, and a model that fails doesn't block the others. If a run is interrupted, dbt-refmerge cleanup --run-id <id> drops whatever it left (the id is in check --json). Verification supports PostgreSQL; scan parses 16 dialects (snowflake, bigquery, duckdb, databricks, redshift, trino, spark, sqlite, tsql, oracle, exasol, clickhouse, and more).

Keep new duplicates out

scan needs no dbt run and no warehouse, so it works as a commit hook or a pull request check (both need 0.2.0 or later):

# .pre-commit-config.yaml
- repo: https://github.com/John-Cusack/dbt-refmerge
  rev: v0.2.0
  hooks:
    - id: dbt-refmerge-scan
# a GitHub Actions step: annotates pull requests at each duplicate
- uses: John-Cusack/dbt-refmerge@v0.2.0
  with:
    adapter: snowflake

See integrations for options and other CI systems.

Documentation

Develop it

Keep the inner test loop focused and in memory:

pip install -e ".[dev,integration]"
python3 -m pytest -q tests/unit/test_odd_scenarios.py  # odd-scenario safety lane
python3 -m pytest -q                                  # unit lane (default)
python3 -m ruff check .
python3 -m mypy --strict src

The default run is the in-memory unit lane and takes a few seconds on a typical development machine. Two slower lanes are opt-in:

python3 -m pytest -q -m fake_dbt      # subprocess tests against tests/fakes/fake_dbt.py

docker run --rm -d --name refmerge-pg -p 5432:5432 \
  -e POSTGRES_PASSWORD=postgres -e POSTGRES_DB=refmerge postgres:16
export REFMERGE_TEST_PG_DSN=postgresql://postgres:postgres@localhost:5432/refmerge
python3 -m pytest -q -m warehouse     # needs Postgres and dbt-postgres
python3 -m pytest -q -m "" --cov      # every lane; enforces the coverage floor

See CONTRIBUTING.md for conventions and the release process, and SECURITY.md to report a vulnerability. IMPROVEMENT_PLAN.md tracks what comes next.

Support

If this saves you an afternoon, buy me a coffee.

MIT license. Requires Python ≥ 3.11 and your own dbt installation.

Release files for dbt-refmerge 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for dbt-refmerge 0.2.0
File Size Uploaded
dbt_refmerge-0.2.0.tar.gz 150.7 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for dbt-refmerge 0.2.0
File Interpreter ABI Platform
dbt_refmerge-0.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 229.5 kB

Release files / dbt_refmerge-0.2.0.tar.gz

Download URL dbt_refmerge-0.2.0.tar.gz
Size 150.7 kB
Tags Source
SHA-256 checksum
How to use checksums
51c515f7677f70f73fb5676fb256b3209138cbb14456f05916a6becdbde4501e
BLAKE2b-256 checksum
How to use checksums
b6ba03ef904acd3214431d707928d2b1ac69d43e219c826cf504be062e2189ca
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 17, 2026.

Transparency log

Release files / dbt_refmerge-0.2.0-py3-none-any.whl

Download URL dbt_refmerge-0.2.0-py3-none-any.whl
Size 78.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
48a485e2d2d581c7c4fc4d6345d53f44389dd0d95168a0fd4f7ddecf6f35b865
BLAKE2b-256 checksum
How to use checksums
4ab6315905798272ec5109c27fd4286a4d979ebe4e1e7e4207772b0f8bf9784b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 17, 2026.

Transparency log

Release history Release notifications | RSS feed

0.3.0

2 release files

This release

0.2.0 This release

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page