DVT INIT
dvt init is the verb you already know: it scaffolds a new project. The DVT version asks you nothing and needs no warehouse — it writes a complete project with a DuckDB default target already wired up, so dvt buildis green before you've configured a single connection.
ONE COMMAND, A WORKING PROJECT
Give it a name and it creates the folder and scaffolds inside it:
$ dvt init sales_dwh Initialized DVT project 'sales_dwh' in sales_dwh + dbt_project.yml + dvt_project.yml + .gitignore + README.md + seeds/sample_orders.csv + models/revenue_by_region.sql + models/sources.yml ✓ added profile 'sales_dwh' (duckdb) to /Users/you/.dbt/profiles.yml Your default target is DuckDB — no warehouse needed: cd sales_dwh dvt build
That's the whole ceremony. No adapter interview, no credential prompts, no "now go set up a database" step — the two closing lines are a real instruction, and following them gives you a green build in seconds. Your warehouse is a sales_dwh.duckdb file that appears at the project root on first build, openable with anything that speaks DuckDB.
IN PLAIN DBT
init starts an interview: pick an adapter from a numbered list, answer host/port/user/password prompts (or skip them and hand-edit profiles.ymllater), and nothing runs until a real warehouse accepts your credentials. DVT's scaffold runs now — DuckDB is the default target out of the box, and real connections join the project when you have them, not before.
OR SCAFFOLD IN PLACE
Already made the folder? Run it bare and the current directory becomes the project, named after itself:
$ cd ecommerce && dvt init Initialized DVT project 'ecommerce' in . + dbt_project.yml + dvt_project.yml + .gitignore + README.md + seeds/sample_orders.csv + models/revenue_by_region.sql + models/sources.yml ✓ added profile 'ecommerce' (duckdb) to /Users/you/.dbt/profiles.yml Your default target is DuckDB — no warehouse needed: dvt build
Either way the project name is normalized to a valid identifier — lowercase, letters and digits and underscores. dvt init Sales-DWH creates a Sales-DWH/ folder whose project and profile are named sales_dwh.
WHAT LANDS ON DISK
The scaffold is small on purpose — every file earns its place:
sales_dwh/ ├── dbt_project.yml # the transform project — byte-pure, no DVT keys ├── dvt_project.yml # DVT's own settings, every default explained ├── .gitignore # target/, logs/, .dvt/, *.duckdb ├── README.md # the same next steps, written down ├── models/ │ ├── revenue_by_region.sql # starter model — builds against the seed │ └── sources.yml # where sources + meta.connection will live ├── seeds/ │ └── sample_orders.csv # five rows, enough to build against ├── macros/ └── tests/
The starter seed and model exist so the first dvt buildhas something real to do. The model's own comments point at the growth path: declare real connections' tables in models/sources.yml (each source names its connection via meta.connection — dvt generate-sources writes that file for you), then switch a model to materialized='f_table' to federate across them.
TWO PROJECT FILES, ON PURPOSE
The scaffold writes both project files, and the split is the point. dbt_project.yml is the transform project — name, paths, materializations — and it stays byte-pure forever: DVT never writes its own keys there, and a DVT key found in it is a config error, not a shrug. dvt_project.yml is DVT's own file, and the scaffold writes it fully populated: every DVT setting — federation_direct, suite_port, ai_enabled, telemetry_enabled — at its real default, each with a comment explaining what that default means. The file is meant to teach, not merely configure.
And it's yours from the moment it exists. If a dvt_project.yml is already sitting in the folder, dvt init never rewrites it — no merge, no reformat, nothing that could lose your ordering, your notes or your commented-out experiments — and the output says so:
· dvt_project.yml was already here — left exactly as you have it
THE DEFAULT PROFILE — MERGED, NEVER CLOBBERED
The ✓ line is the third thing initdoes: it merges an entry under the project's name into your profiles.yml — the canonical one at ~/.dbt/profiles.yml (or $DBT_PROFILES_DIRwhen you've set it), so everything that already reads that file keeps working. The entry is a single DuckDB target pointing at the .duckdb file at your project root:
sales_dwh:
target: dev
outputs:
dev:
type: duckdb
path: /Users/you/projects/sales_dwh/sales_dwh.duckdb
schema: main
threads: 4Merged means merged. Every profile already in the file is preserved; if an entry named sales_dwh already exists it is left alone and used as-is; and whenever the file is rewritten, the previous version is kept beside it as a timestamped .bak:
✓ added profile 'sales_dwh' (duckdb) to /Users/you/.dbt/profiles.yml (previous kept at profiles.yml.20260803-101502.bak) # or, when the entry already existed: ✓ profile 'sales_dwh' already exists in /Users/you/.dbt/profiles.yml — using it as-is
And if the file exists but can't be parsed, init refuses to touch it rather than guess — fix it first; refusing to rewrite a file I can't read.
WHEN IT REFUSES
init is deliberately un-clever about existing work. A named folder that already has contents is refused, and a folder that already holds a dbt_project.yml is already a project — scaffolding over it could only do harm:
$ dvt init sales_dwh dvt init: sales_dwh/ already exists and is not empty $ dvt init dvt init: dbt_project.yml already exists here — this is already a project
Both exit nonzero and write nothing. The one exception you've already seen: an existing dvt_project.ymlin an otherwise-fresh folder isn't an error — it's kept, exactly as you have it.
REFERENCE — THE WHOLE SURFACE
One optional positional, no flags, no prompts. Both forms print the same ledger: a + per file created, a · per file kept, a ✓ for the profile.
| ARGUMENT | TAKES | WHAT IT DOES |
|---|---|---|
| <name> | optional | Project folder to create and scaffold into — refused if it already exists and is not empty. Omit it to scaffold the current folder in place under its own name. Either way the project/profile name is sanitized to lowercase letters, digits and underscores. |