SEEDS, SNAPSHOTS, TESTS & JINJA

Everything in a dbt project beyond models works in DVT — most of it passes straight through to dbt unchanged, and seeds get a major upgrade through Sling.

SEEDS — SUPERCHARGED VIA SLING

dvt seedreplaces dbt's row-by-row seed loading with Sling bulk loads. That changes what seeds can be:

  • Formats beyond CSV: tsv, parquet, json, jsonl, avro, arrow, xlsx — drop the file in seeds/ and run.
  • Any target: --target loads seeds to any output in your profile, including cloud buckets (as parquet objects).
  • Speed: bulk loading moves millions of rows in seconds, not minutes — 2.1M rows / 138MB in ~10s in our benchmark.
  • Column types: dbt-native +column_types in dbt_project.yml is honored and passed to Sling.

Column names are snake_cased by default. DVT applies Sling's snake-case mode on every seed load (override with --column-casing) — "Transaction Date" becomes transaction_date on every engine. This is what makes the same seed load identically on PostgreSQL, Oracle, Databricks, and everything in between; spaced or mixed-case headers break several engines otherwise.

dvt seed                          # all seeds → default target
dvt seed --select my_seed         # one seed
dvt seed --target dbx_dev         # seeds → another engine
dvt seed --target s3_lake         # seeds → a bucket, as parquet

SNAPSHOTS — DBT NATIVE

Snapshots run unchanged through dbt on the default target — timestamp and check strategies, invalidation, the full feature set:

{% snapshot orders_snapshot %}
{{ config(
    target_schema='snapshots',
    unique_key='order_id',
    strategy='timestamp',
    updated_at='updated_at'
) }}
select * from {{ ref('stg_orders') }}
{% endsnapshot %}

Run with dvt snapshot — identical to dbt snapshot.

TESTS — DBT NATIVE

Generic tests (unique, not_null, accepted_values, relationships) and singular tests work on every model — including federation models, since their results are real tables on the target engine by the time tests run:

models:
  - name: fct_cross_engine_sales     # a federation model
    columns:
      - name: order_id
        data_tests:
          - unique
          - not_null

dvt test and the test phase of dvt build behave exactly like dbt — with one honest exception: tests declared on foreign-connection sourcesare skipped with a loud warning, because dbt compiles them against the default target where that relation doesn't exist. Model tests, including tests on federation models, run normally.

ANALYSES — DBT NATIVE

SQL files in analyses/ compile with dvt compile but never materialize — same as dbt. Useful for ad-hoc queries that should version alongside the project.

JINJA & MACROS — DBT NATIVE

The entire Jinja layer is dbt's: ref(), source(), var(), env_var(), custom macros, packages from dbt Hub — all of it renders before DVT ever sees the SQL. Federation models are plain Jinja-templated models that happen to compile to DuckDB dialect:

{{ config(materialized='f_table') }}

select
    o.order_id,
    {{ cents_to_dollars('o.amount_cents') }} as amount
from {{ source('pg_sales', 'orders') }} o
join {{ source('snowflake_finance', 'fx_rates') }} fx
  on o.currency = fx.currency

One caveat: macros used inside federation models must emit DuckDB-compatible SQL, since that's the dialect federation models are written in. See the dual-dialect rules.