sqlassert-dbt
Prove your dbt tests from the SQL, and skip the ones that can't fail.
A unique or not_null test scans a table in the warehouse on every run, and
it only tells you about today's data. Many of those tests follow from the SQL
itself: customer_id is unique because the model groups by it, status is
never null because of a coalesce. sqlassert
proves them from the compiled model before anything runs, so dbt can leave them
out: faster CI, a smaller warehouse bill, and the same guarantee for any
data, not just the rows there today.
pip install sqlassert-dbt
Alpha: the markers and dbt test mappings are stable; the CLI output may change.
Skip the tests the SQL proves
Run dbt through the plugin:
sqlassert-dbt build . -- --target prod # or: sqlassert-dbt test
It runs dbt compile, checks every model, then runs dbt build (or
dbt test) with each proved test passed as --exclude. Arguments after --
go to dbt unchanged. The exit code is dbt's when dbt fails, otherwise the
check's.
The tests of the sources, seeds and models a model reads are trusted as
facts, since dbt build runs them first in the same invocation. If the
arguments after -- select nodes (--select, --exclude, --selector, ...),
an upstream test may not run, so none is trusted.
Check without dbt
check reads only target/manifest.json, so dbt does not need to be installed
where it runs (a CI step after dbt compile, say):
$ dbt compile
$ sqlassert-dbt check . --trust-upstream-tests
models/customers.sql:12: UNKNOWN /**ASSERT NOT NULL(first_name)**/ (customers)
Proved statically (a test here can be skipped):
models/schema.yml unique_stg_customers_customer_id (test on stg_customers)
Not proved (the warehouse run still checks these):
models/schema.yml accepted_values_stg_orders_status__placed__shipped__returned (test on stg_orders): its Property is not proved from the SQL
Proved but untested (schema.yml additions):
models/schema.yml customers.customer_id: not_null
Three lists come out:
- Proved statically: tests the SQL already guarantees. Skip them.
- Not proved: tests that still need the warehouse. Nothing is wrong; the SQL alone can't show the property.
- Proved but untested: properties sqlassert proved that no test states.
Free
schema.ymladditions, which cost nothing to keep.
| Option | |
|---|---|
--trust-upstream-tests |
Treat passing tests of upstream nodes as facts (true under dbt build). Without it, a dbt-untrusted-upstream-tests warning lists them. |
--require-proved |
Fail when any test is not proved, not only when a marker is UNKNOWN. |
--explain |
Print each proof, and each failed proof. |
--dialect NAME |
Analyze under this dialect instead of the adapter's. |
--manifest PATH |
Read another manifest (default PROJECT/target/manifest.json). |
Exit codes: 0 every marker proved; 1 a marker is UNKNOWN or an error was
reported (unproved tests fail it only with --require-proved); 2 the
manifest cannot be read.
What it understands
| dbt | sqlassert Property |
|---|---|
unique |
Unique Set |
not_null |
Not Null |
accepted_values |
Enum |
relationships |
Referential Coverage (Foreign Key) |
dbt_utils.unique_combination_of_columns |
Non-Null Unique Set (it counts NULL equal to NULL) |
contract primary_key, unique, not_null, foreign_key |
the same Properties |
A model's own tests are what gets proved. Upstream tests are evidence, used
only when they fail on any failing row: not a test with severity: warn, a
where: config, or error_if/fail_calc thresholds. A constraint counts only
on a contracted table whose adapter enforces it.
Markers in models
You can also write sqlassert markers straight into a model, and they are checked and reported at their line in the model file:
-- models/customer_orders.sql
select c.customer_id, c.first_name, o.order_id
from {{ ref('stg_orders') }} o
/**ASSERT MANY TO ONE**/ join {{ ref('stg_customers') }} c
on o.customer_id = c.customer_id
If someone later loads duplicate customers upstream, or drops the unique
test that made this provable, the marker turns UNKNOWN and CI fails before
the join fans out in production. See the
sqlassert README for every
marker.
Details
- Manifest: only the latest schema (v12, written by dbt 1.8 to 1.12).
- Ephemeral models are analyzed where dbt inlined them.
- Incremental models are analyzed in both
is_incremental()branches. A test holds only if it holds in both, and a key only under amergeordelete+insertstrategy on thatunique_keywith noincremental_predicates. The other branch is rendered without dbt only when the model usesref,source,this,configandis_incremental()alone; otherwise it is reported unanalyzed. - Adapters: analyzed when sqlassert models their dialect (DuckDB, PostgreSQL, MySQL, Snowflake, BigQuery, Databricks / Spark, Redshift, Trino).
- A model with markers but no compiled code is an error, not skipped.
License
MIT
Metadata
Release files for sqlassert-dbt 0.3.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| sqlassert_dbt-0.3.1.tar.gz | 42.8 kB | With provenance | Details for sqlassert_dbt-0.3.1.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| sqlassert_dbt-0.3.1-py3-none-any.whl | Python 3 | none | any | Details for sqlassert_dbt-0.3.1-py3-none-any.whl |
Total release size: 77.6 kB
Release files / sqlassert_dbt-0.3.1.tar.gz
| Download URL | sqlassert_dbt-0.3.1.tar.gz |
|---|---|
| Size | 42.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
19cdf2468e5169928dde34112ba46cbfaaec06361981234c964a461095cbc49a
|
|
BLAKE2b-256 checksum How to use checksums |
182aaf21ff7d3c07f5f0090131321ae542d44d1a74f09acc9ddcff61df566405
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
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 Nov 9, 2026.
Transparency logRelease files / sqlassert_dbt-0.3.1-py3-none-any.whl
| Download URL | sqlassert_dbt-0.3.1-py3-none-any.whl |
|---|---|
| Size | 34.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
6b211bc3fbefe949da87e1d18f46dd693e98eb5a3e032af62eb791fc538239c9
|
|
BLAKE2b-256 checksum How to use checksums |
5193765ff2b89d760ef4066d4d9852a75581fe6cb8208538f4741c1f581c5df2
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
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 Nov 9, 2026.
Transparency logSecurity for sqlassert-dbt 0.3.1
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.
Full provenance
Both files in this release have been uploaded with provenance metadata.
Attestation for sqlassert_dbt-0.3.1.tar.gz
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 Nov 9, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.