THE DATA CATALOG
This is dbt docs, taught to see past one adapter. Where stock dbt catalogs only the default target, dvt docs generate walks every connection in your profile — Postgres, Oracle, Snowflake, buckets, all of them — and builds one catalog: every model, source and column, engine-stamped, with lineage across the whole graph.
Build it, then open it
dvt docs generate # build the cross-engine catalog into target/
dvt serve # bring up the project suite…
# …then open http://localhost:46100/catalogThe catalog is one app in the project suite — a path on one origin, not a port of its own. dvt serve starts the suite on the project's suite_port (46100 unless dvt_project.yml says otherwise), and the catalog answers at /catalog.
If muscle memory types dvt docs serve, DVT prints one line pointing you at dvt serve — the standalone verb has moved into the suite. The full story of what generate does is on the dvt docs command page.
What you get
- engine-stamped columns — every relation is cataloged from its own engine's information schema — types as the engine reports them, across all your connections at once.
- cross-engine lineage — the graph doesn't stop at an engine boundary: a gold model on Databricks traces back through DuckDB compute to its Postgres and Oracle sources.
- model and source docs — descriptions from your yml files, rendered exactly as dbt users expect — this is still the dbt docs experience underneath.
- one theme with the suite — light and dark follow one cookie across the whole suite — flip it in any app and every app agrees. The light mode is the calm grey pair, never white.
The source-metadata store — dvt metadata
The visual catalog has a sibling on disk: .dvt/metadata.duckdb, the source-metadata store. It is DVT's memory of what its sources looked like each time it read them — columns, types and constraints, kept as versions. The dvt metadata command family maintains it, with at most three catalog queries per connection and one DuckDB write. Zero AI involved.
dvt metadata refresh --all # re-read every catalog dvt metadata refresh pg_docker # just one connection dvt metadata status # what changed upstream dvt metadata propagate --dry-run # plan only, free dvt metadata propagate pg_docker # plan, then consent dvt metadata export -f xlsx -o catalog.xlsx dvt metadata export -f json --from 1 --to 4
- refresh — read, never write — re-reads a connection's catalog into the store and highlights new column versions or dropped tables. sources.yml is never touched — that is the whole point of a verb separate from generate-sources: find out what changed upstream without risking your declarations. Buckets have no catalog to query, so refresh reads object shapes instead — up to --probe N of them (default 25) — and always states how many of how many it opened; the rest are recorded by name, never guessed at.
- status — what the store knows — tables and versions per connection, every table that changed since DVT last saw it, and any DVT staging leftovers it flagged (recorded, never dropped).
- propagate — plan first, consent second — plans what carrying recorded changes through would touch: which sources.yml entries change, which downstream models are affected via the DAG, which incremental models get fully refreshed, and which models the change broke — broken models are refused while the rest proceeds. Nothing is written or run until you say yes; --dry-run prints the plan and stops, --yes is for scripts, and every edited yml keeps a timestamped .bak beside it.
- export — the catalog as a report — Sources, Columns, Constraints and Changes as CSV (four files into a directory), XLSX (one workbook, four sheets) or JSON (one document). --from/--to bound the version numbers per table, --since bounds changes by detection time, --connection and --table narrow the scope.
The store is built by dvt metadata refresh --all — or as a side product of any dvt generate-sources run. It also powers dvt generate-base-views, which writes one bronze model per source table from the exact columns the store recorded — both are documented on the sources page. For the full walkthrough — including what propagate refuses, and why — see the dvt metadata command page.
Good to know
- regenerate after structural changes — renames, new models, new connections — dvt docs generate refreshes the catalog; the api-portal and the catalog both read its output.
- the navbar names the app — the catalog says DATA CATALOG; the full product name lives on the hub — each app names itself.
- read-only by design — the catalog never writes anything anywhere; it's safe to expose internally when your team needs shared documentation (see the enterprise page for the hosting posture).