DVT SYNC
dvt sync sets up everything DVT needs on this machine — the execution engine, an adapter and native driver for every warehouse in your profiles.yml, and the Sling engine that moves data between systems — all into the one Python environment you're already standing in. Run it once after install, and again whenever anything changes: it only ever does what's missing.
YOUR FIRST SYNC
From inside a project, no flags needed. dvt sync reads dbt_project.ymlfor the profile name, reads that profile's outputs from profiles.yml, and works out the rest itself. Here it is on a project with a Postgres output and a DuckDB output:
$ dvt sync
Sync plan (execution follows — no prompt; the invocation is the consent):
→ env: install adapters[postgres,duckdb]
→ sling: install wrapper (sling>=1.5.15) + fetch engine (~100 MB)
→ duckdb: ensure extensions (httpfs, json, postgres_scanner)
→ project: write macros/dvt_federation_materializations.sql
⏳ fetching the Sling engine (~100 MB, one time — slow networks take minutes)...
============================================================
DVT Environment Sync
============================================================
✅ Detect environment: Darwin arm64, Python 3.11.9 (venv)
• Project: /Users/you/analytics
• Profile: analytics
• Profiles dir: /Users/you/.dbt
✅ Create directories: Directories ready: /Users/you/.dvt
✅ Install adapters: Installed: adapters[postgres,duckdb]
✅ Install bucket packages: No bucket packages to install
✅ Install Python model packages: No Python models in project
✅ Download Sling: Sling ready: /Users/you/analytics/.venv/bin/sling
✅ Install DuckDB extensions: DuckDB extensions: httpfs, json, postgres_scanner
✅ Install compatibility macros: Installed macros/dvt_federation_materializations.sql
✅ Validate credentials: Warnings: AWS credentials not found; GCP credentials not found; Azure credentials not found
✅ Test connections: All output configs valid
============================================================
Plan reconciliation:
✓ as planned: env: install adapters[postgres,duckdb]
✓ as planned: sling: install wrapper (sling>=1.5.15) + fetch engine (~100 MB)
✓ as planned: duckdb: ensure extensions (httpfs, json, postgres_scanner)
✓ as planned: project: write macros/dvt_federation_materializations.sql
============================================================
✅ Environment is ready for DVTOne command, one environment: adapters for both engines, their native drivers, the DuckDB extensions federation needs, and the Sling engine. The credential lines are warnings, never failures — you only need cloud credentials when your project actually reads cloud storage.
IN PLAIN DBT
You install one adapter package per warehouse yourself — pip install dbt-postgres, then pip install dbt-snowflake — and then discover they disagree about dbt-core versions and native drivers, and the conflicts are yours to resolve. The usual endgame is one virtualenv per warehouse and a Makefile to remember which is which. dvt sync reads profiles.yml and installs a set that already agrees with itself, into one environment.
THE PLAN COMES FIRST
sync never mutates your environment quietly. Before the step loop touches anything, it prints its full plan — every install, every removal, with the exact version specs it will pass. There is no prompt: running the command is the consent. What keeps the plan honest is the second half — after the steps run, the summary reconciles what was done against what was planned, line for line. A mutation that was planned but didn't happen, or happened but was never planned, gets a loud warning line either way:
Plan reconciliation: ✓ as planned: env: install adapters[postgres,duckdb] ⚠ planned but NOT done: sling: fetch engine (~100 MB) (see the failed step above)
So the transcript of any sync answers both questions that matter afterwards: what did it intend to change, and did it change exactly that.
RUN IT AGAIN ANY TIME
sync is idempotent. Every step checks before acting — adapters are probed by importing them (the exact test the engine performs at run time), the Sling engine is probed by executing it, the compatibility macros are compared byte-for-byte. A re-run on a healthy environment plans almost nothing and mutates nothing:
$ dvt sync Sync plan (execution follows — no prompt; the invocation is the consent): → duckdb: ensure extensions (httpfs, json, postgres_scanner) ============================================================ DVT Environment Sync ============================================================ ✅ Detect environment: Darwin arm64, Python 3.11.9 (venv) • Project: /Users/you/analytics • Profile: analytics • Profiles dir: /Users/you/.dbt ✅ Create directories: Directories ready: /Users/you/.dvt ✅ Install adapters: All adapters already installed ✅ Install bucket packages: No bucket packages to install ✅ Install Python model packages: No Python models in project ✅ Download Sling: Sling ready: /Users/you/analytics/.venv/bin/sling ✅ Install DuckDB extensions: DuckDB extensions: httpfs, json, postgres_scanner ✅ Install compatibility macros: Compatibility macros already installed ✅ Validate credentials: All cloud credentials found ✅ Test connections: All output configs valid ============================================================ Plan reconciliation: ✓ as planned: duckdb: ensure extensions (httpfs, json, postgres_scanner) ============================================================ ✅ Environment is ready for DVT
That makes sync the standing repair verb, not just the day-one one. Added a Snowflake output to profiles.yml? Re-run sync. New teammate cloned the repo? sync. A run ever tells you the environment looks damaged? sync. It converges on the same working state from any starting point.
IN PLAIN DBT
There is no converge verb. When an environment drifts — a driver upgrade, a colleague's pip install, a half-finished setup — repair is manual archaeology: read the traceback, guess the package, pin, retry. dvt sync re-derives the whole environment from profiles.yml and fixes exactly the delta.
SELF-HEALING — THE CORRUPTED DOWNLOAD
The Sling engine is a ~100 MB binary that downloads on first use — and a download that dies mid-fetch leaves a truncated binary on disk that looksinstalled. Version metadata can't tell the difference, so syncdoesn't ask metadata — it executes the binary. A corrupted engine fails that probe, gets deleted, and is fetched again, visibly:
⚠️ removed 1 truncated Sling engine(s) — re-fetching
⏳ fetching the Sling engine (~100 MB, one time — slow networks take minutes)...This is also why sync takes the download up front instead of declaring victory early: deferred to the middle of your first real query, that fetch would be racing every connection timeout you have. sync eats the wait now, once, where you can watch it.
THE COLLISION GUARD
If an upstream per-engine dbt distribution — dbt-postgres, dbt-snowflake, and friends — is already installed in the environment, it shadows DVT's own adapters and the two fight over the same import namespace. syncdoesn't leave that landmine armed: every colliding distribution goes on the plan and is removed, always with the reason stated, never silently:
Sync plan (execution follows — no prompt; the invocation is the consent):
→ env: uninstall dbt-snowflake (upstream per-engine dist shadows DVT's adapters)
removed dbt-snowflake: upstream per-engine dist shadows DVT's adaptersThen comes the verify pass: every adapter your profile needs must actually import — that import is exactly what the engine's factory will do at run time, so it is the only honest test. Any adapter that still fails is named, and the step (and sync's exit code) fails with it. An output type sync doesn't recognize is reported by name, never guessed at.
WHAT ELSE RIDES ALONG
Bucket packages. A profile that declares cloud-storage connectors gets their transports installed too — s3, gcs, and azure each map to their own package, installed only when your profiles.yml actually declares that connector.
Python model packages. syncscans your project's Python models — explicit dbt.config(packages=[...])declarations first, then top-level imports — and installs whatever's missing. With a guard: a requirement set that would move DVT's own foundational packages is refused with instructions to pin compatible versions in your models, never installed anyway.
Compatibility macros. sync writes macros/dvt_federation_materializations.sql into the project so that plain dbt run — an IDE extension, CI calling dbt directly — hitting an f_table model fails with a clear "run it with dvt run" instead of a baffling "materialization not found".
Connection check. Every output in your profile is validated as a well-formed connection config, and a broken one is named output-by-output — so a typo in profiles.yml surfaces here, not three steps into your first run.
Every engine in your profile gets the full treatment — Postgres, Redshift, Snowflake, BigQuery, Athena, Databricks, DuckDB (MotherDuck included), Trino, ClickHouse, Oracle, SQL Server, Fabric, SQLite, MySQL, MariaDB, StarRocks, Exasol. The per-engine details live on the adapter pages.
REFERENCE — EVERY FLAG
All flags are optional — the whole point of syncis that the bare invocation figures everything out from the project it's standing in.
| FLAG | DEFAULT | WHAT IT DOES |
|---|---|---|
| --project-dir <path> | current directory | The project to sync for — where dbt_project.yml lives. --dbt-project is a shipped alias with the same meaning; scripts that type either keep working. |
| --profiles-dir <path> | resolved | Where profiles.yml lives. The default is the same resolver every DVT command uses — $DBT_PROFILES_DIR, then a project-local profiles.yml, then ~/.dbt — so sync installs drivers for the same file everything else reads. |
| --profile <name> | auto-detected | Which profile's outputs decide the adapter set. Auto-detected from dbt_project.yml's profile: key (falling back to the project name). |
| --python-env <path> | the active environment | The Python environment bucket and Python-model packages install into. Adapters always install into the environment dvt itself runs in — one environment is the design, not an option. |
| --sling-version <ver> | bundled default | Pin the Sling version sync installs instead of the release it ships tested against. |