Validate
import { Aside } from ‘@astrojs/starlight/components’;
sqlanvil validate checks that every model’s SQL is valid — syntax, missing tables, missing
columns, type errors — before you run the project, without executing or materializing anything.
It’s the fast feedback loop: catch the typo in seconds instead of partway through a run.
sqlanvil validate # validate the whole projectsqlanvil validate --actions my_model --include-depssqlanvil validate --environment dev # use a named environment's config + credentialssqlanvil validate --json # machine-readable resultsrun --dry-run is an alias on PostgreSQL/Supabase/MySQL — it validates instead of executing.
(On BigQuery, run --dry-run keeps BigQuery’s own server-side dry-run.)
How it works
Section titled “How it works”SQLAnvil walks your DAG in dependency order and validates each model against the warehouse’s own
planner — EXPLAIN on PostgreSQL/Supabase/MySQL, a dry-run on BigQuery — so there’s no separate
SQL engine to drift from your warehouse’s behavior.
The trick to validating a whole project (where model B selects from model A, which doesn’t exist
yet) is an isolated shadow namespace: SQLAnvil compiles into a temporary, timestamped schema
(a dataset on BigQuery, a database on MySQL), and after each model validates it materializes an
empty stub (CREATE TABLE … WITH NO DATA, or LIMIT 0) so the next model’s references resolve.
The shadow namespace is dropped when validation finishes — nothing touches your real tables.
Results
Section titled “Results”Each action is reported as one of:
| Status | Meaning |
|---|---|
| PASS | The model’s SQL planned cleanly. |
| FAIL | The model’s own SQL is invalid (with the error message + line/column). |
| BLOCK | Skipped because an upstream model failed — so this one can’t be meaningfully checked. |
| SKIP | Not validated (e.g. an operations block — arbitrary, possibly side-effecting SQL). |
validate exits non-zero if anything FAILed or was BLOCKed, so it drops straight into CI.
Script actions (1.20+)
Section titled “Script actions (1.20+)”Python script actions get their own validation — the Python
analog of EXPLAIN, run without executing the script: the resolved interpreter must satisfy
pythonVersion, every requirements: spec must be satisfied by the installed packages (checked
offline — nothing is installed), and the script must parse. A failing script action reports
FAIL with each problem on its own line (“requests is not installed (need >=2.31)”), and
its dependents are BLOCKed, exactly like models.
$ sqlanvil validate PASS analytics.stg_orders FAIL analytics.orders column "totl" does not exist (line 4, col 8) BLOCK analytics.daily_revenue — blocked by an upstream failure
1 passed, 1 failed, 1 blockedThe FAIL vs BLOCK split keeps the signal clean: one real error doesn’t bury you in a cascade of confusing failures — you see the one model to fix.