DVT LS, SHOW & DEBUG

Three verbs for looking before you leap: dvt ls tells you what a selection would match, dvt show previews the rows a model would produce, and dvt debug proves your connections actually work. If you know these verbs from dbt, you already know how to drive them — same flags, same selection syntax, same behavior — and none of the three ever materializes or changes a thing.

$ dvt ls --select orders+
analytics.marts.orders
analytics.marts.fct_order_margins
analytics.not_null_orders_order_id
analytics.unique_orders_order_id

That's the spirit of the whole page: ask first, spend later. Each verb gets its own section below, and the full flag tables are at the end.

DVT LS — RESOLVE THE SELECTION, SPEND NOTHING

dvt ls resolves your selection exactly as a run would — same selector engine, same graph — then prints what it matched instead of executing it. It is the safe way to check a --select expression before you spend a warehouse on it: the four nodes above are precisely what dvt run --select orders+ would build and dvt build would test.

dvt listis the same command, letter for letter. And because the graph is the project's whole graph, everything shows up as a node — models, tests, seeds, snapshots, and your sources on every connection. A federated model that reads Postgres and Snowflake in one query is just another line here; selection reaches across engines the same way run does.

--output changes what each matched node prints as. path gives you the file on disk — handy for piping into an editor:

$ dvt ls --select orders+ --resource-type model --output path
models/marts/orders.sql
models/marts/fct_order_margins.sql

And json gives you one object per line, with --output-keys choosing which fields ride along — made for jq and CI scripts:

$ dvt ls --resource-type model --output json --output-keys "name resource_type"
{"name": "stg_orders", "resource_type": "model"}
{"name": "stg_payments", "resource_type": "model"}
{"name": "orders", "resource_type": "model"}
{"name": "fct_order_margins", "resource_type": "model"}

One DVT-ism worth knowing: like every graph verb, ls begins from a passing dvt parse. A project that doesn't parse answers with the parse error itself — named file, named line — never a selector stack trace on top of a broken manifest.

DVT SHOW — PREVIEW ROWS, MATERIALIZE NOTHING

dvt show compiles a model, runs it, and prints a preview of the rows that came back. Nothing lands in the warehouse — this is a look, not a build. Five rows by default:

$ dvt show --select orders
14:07:31  Previewing node 'orders':
| order_id | customer_id | order_date | status  |
| -------- | ----------- | ---------- | ------- |
|     9110 |         214 | 2026-07-30 | queued  |
|     9111 |          58 | 2026-07-30 | shipped |
|     9112 |         214 | 2026-07-31 | shipped |
|     9113 |          17 | 2026-08-01 | shipped |
|     9114 |          42 | 2026-08-01 | queued  |

--limit raises or lowers the row count (-1 means no limit at all), and the limit rides inside the query itself, so previewing a model over a billion-row table stays cheap:

$ dvt show --select orders --limit 20

The other way in is --inline — an ad-hoc query instead of a file, with ref() and source()fully available. It's the quickest possible answer to "what's actually in this model right now?":

$ dvt show --inline "select max(order_date) as latest_order from {{ ref('orders') }}"
14:09:02  Previewing inline node:
| latest_order |
| ------------ |
| 2026-08-01   |

--output json switches the preview from the table to JSON for scripts, and -f / --full-refreshpreviews an incremental model as the full rebuild it would be — again without touching what's materialized.

One boundary to know: show looks at your project through the default target, project semantics included. When you want raw, engine-native SQL on any named connection — no Jinja, no project, just the engine — dvt exec is the sibling built for exactly that.

DVT DEBUG — PROVE THE WIRING

dvt debug starts exactly where you expect: the checks you know, against the default target (or --target). Then DVT adds one more line — the same connection tested through Sling, the engine that moves data between systems. DVT moves your data through both layers, so debug proves both:

$ dvt debug
profiles.yml file [OK found and valid]
dbt_project.yml file [OK found and valid]

Required dependencies:
 - git [OK found]

Connection:
  host: prod-pg.internal
  port: 5432
  user: analytics
  database: prod
  schema: analytics
  Connection test: [OK connection ok]

All checks passed!
  Sling (data movement) [pg_prod]: OK connection ok

A connection can pass the adapter handshake and still fail bulk data movement (or the reverse) — a firewall rule, a driver, a credential scoped to one protocol. Catching that here costs seconds; catching it mid-run costs the run.

The real upgrade is --all: every output in your profile, both layers, in parallel, one screen. Buckets show n/a on the adapter column — they hold files (csv, parquet, json, jsonl), so Sling is their only layer:

$ dvt debug --all
Testing all connections for profile 'analytics' (adapter + Sling) ...
✅ duckdb_local  ✨ Adapter: OK    ⚡️ Sling: OK    duckdb
✅ pg_prod       ✨ Adapter: OK    ⚡️ Sling: OK    postgres
✅ s3_landing    ✨ Adapter: n/a   ⚡️ Sling: OK    s3
❌ sf_finance    ✨ Adapter: FAIL  ⚡️ Sling: FAIL  snowflake
   ↳ 250001 (08001): incorrect username or password was specified

3/4 connections fully operational

Failures come with the reason, not boilerplate — the engine's own last meaningful line, like the Snowflake auth error above. A connection whose adapter simply isn't installed says so and names the fix: adapter not installed — run `dvt sync`.

IN PLAIN DBT

dbt debug tests exactly one connection: the active target. Every other output in profiles.yml lives on faith until a run dies against it. A federated project lives across connections — so DVT tests the whole profile at once, every output on both layers, and tells you 3/4instead of letting number four ambush Monday's run.

dvt diagnose is the same full matrix, kept as a spelling — it says so and runs it:

$ dvt diagnose
`dvt diagnose` is an alias of `dvt debug --all`

Testing all connections for profile 'analytics' (adapter + Sling) ...

When the profile includes engines with a native bulk-load lane, debug also states whether that lane is available on thismachine — with the consequence spelled out, not implied. Oracle's sqlldr, for example:

Engine preflight:
  oracle: sqlldr found — bulk load lane available

If the tool is missing, the row says what that costs (Oracle loads fall back to a much slower cursor lane) and where the tool comes from — so "why is this load slow?" gets answered before the load, not after.

Two last habits worth building on. Debug is deliberately never parse-gated — it is one of the tools you fix a broken project with, so it answers even when nothing else will. And the exit code is honest: 0 only when every tested connection is fully operational, 1 otherwise — which makes dvt debug --all a one-line health gate for CI.

REFERENCE — DVT LS FLAGS

FLAGTYPEDEFAULTWHAT IT DOES
-s, -m, --select, --models, --modeltupleeverythingThe nodes to include — the same selection syntax run uses, resolved by the same selector engine. Graph operators (+, @), tag:, source:, path selectors: all of it.
--excludetupleThe nodes to leave out of the resolved selection.
--selectorstringA named selector from selectors.yml instead of an inline expression.
--resource-types, --resource-typetypeall typesRestrict the listing to these resource types (model, test, seed, snapshot, source, ...). --exclude-resource-types is the mirror.
--output[name|path|selector|json]selectorHow each matched resource prints: bare name, file path, dotted selector form, or one JSON object per line.
--output-keystupleall keysWith --output json, which keys each object carries — e.g. 'name resource_type' for lean script input.

The engine-wide options — project and target, state and deferral, logging — apply here exactly as they do on run; dvt ls --help prints the complete set.

REFERENCE — DVT SHOW FLAGS

FLAGTYPEDEFAULTWHAT IT DOES
-s, --selecttupleThe model (or models) to preview. Same selection syntax as everywhere else.
--inlinestringPreview the results of this SQL instead of a file. ref() and source() work inside it.
--limitinteger5How many rows to preview. -1 removes the limit entirely. The limit is applied inside the query, so big models stay cheap to peek at.
--output[json|text]textThe preview as a readable table, or as JSON for scripts.
--introspect / --no-introspectflag pairintrospectWhether to run introspective queries while compiling the preview.
-f, --full-refreshflagoffPreview an incremental model as the full rebuild it would be — without materializing anything.

The same engine-wide options apply; dvt show --help has the full list.

REFERENCE — DVT DEBUG FLAGS

FLAGTYPEDEFAULTWHAT IT DOES
--allflagoffTest every output in the profile, both layers (adapter + Sling), in parallel. dvt diagnose is an alias for exactly this.
--target, -tstringprofile's defaultWhich single output to test on the parity path. Without --all, debug tests this one connection on both layers.
--projectstringfrom dbt_project.ymlThe profile name to test. Normally inferred from the project; pass it explicitly when running outside one.
--project-dirpath.The project directory to read dbt_project.yml from.
--profiles-dirpath~/.dbtWhere to find profiles.yml, when it isn't in the standard place.

On the single-target path, any extra flags you pass ride through to the underlying connection check untouched — debug never eats a flag it doesn't know.