duckdb-dbt
Skill1 starsChanged 15 days agoMITView on GitHub
Run dbt v2 on DuckDB with the built-in adapter. Covers the v1 package split, driver and storage proof, profiles, extensions, materializations, incremental strategies, hooks, concurrency, catalogs, and migration. Use when the user mentions dbt, dbt-duckdb, a dbt profile, or a dbt project on DuckDB.
- Installs packages
In this repository14 other files it gives its agents.
- duckdb-docsSkill
- duckdb-extensionsSkill
- duckdb-filesSkill
- duckdb-lakehouseSkill
- duckdb-migrateSkill
- duckdb-profileSkill
- duckdb-pythonSkill
- duckdb-quackSkill
- duckdb-searchSkill
- duckdb-sessionSkill
- duckdbSkill
- duckdb-spatialSkill
- duckdb-sqlSkill
- duckdb-variantSkill
The file
Show its rules and text
We split this skill into the rules it gives an agent
24 rules. About 0 are common, 7 are distinctive, and 17 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈7
Distinctive · estimate
This author's own choices. Worth a look.
17
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- could be automatic: a setting could enforce it
- Distinctive: line 14
Before configuring a project, verify the installed adapter:
- Very specific: line 20
If dbt v2 is installed, it outputs a single line (such as dbt 2.0.9) with no Core or Plugins block.
- Distinctive: line 34
Before modifying project code, prove the binary and driver stack:
- Very specific: line 36
Run dbt --version; the output must be a single 2.x line.
- Very specific: line 37
Run dbt debug; the output must report duckdb (remote).
- Very specific: line 38
Run dbt show --inline "select version()" to verify the engine version.
- Very specific: line 39
If the reported engine is not 2.0, run dbc install duckdb to install the system driver.
- Very specific: line 100
If duplicate source keys match a single target row during merge, the query aborts:
- Very specific: line 119
When updating incremental models, note that DuckDB FTS triggers capture INSERT and DELETE, but not UPDATE.
- Distinctive: line 123
If running on distributed workers, pin the pipeline to a single local worker with a persistent volume, or persist storage to S3, Parquet, …
- Very specific: line 143
Run dbc install duckdb if the project uses DuckDB 2.0 files or extensions.
- Very specific: line 146
If older readers must open output files, pin storage using DuckDB CLI ATTACH ...
- Very specific: line 147
Keep the v1 environment until a complete dbt build passes models and tests.
- Very specific: line 149
Verify feature parity: Python models and materialized views are not implemented.
- Very specific: line 153
Do not call a dbt-duckdb install a dbt v2 install.
- Very specific: line 154
Do not read dbt --version as an adapter list.
- Distinctive: line 155
Do not point a 1.5.4 bundled driver at a storage-69 file.
- Very specific: line 156
Do not claim a profile key controls STORAGE_VERSION.
- Very specific: line 157
Do not use merge or delete+insert without unique_key.
- Distinctive: line 158
Do not run two writers against one local file.
- Distinctive: line 159
Do not put a local warehouse on an ephemeral worker.
- Distinctive: line 160
Do not rebuild a model with a search index without rebuilding the index.
- Very specific: line 161
Do not use --compute inline or sidecar with DuckDB.
- Very specific: line 190
Read duckdb-lakehouse for catalog selection, duckdb-search for index freshness, and duckdb-migrate for storage pins.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
dbt on DuckDB
Two products share the name. dbt-duckdb is the v1 Python adapter. dbt v2 packages its own built-in DuckDB adapter inside dbt and does not use dbt-duckdb.
Before configuring a project, verify the installed adapter:
dbt --versionIf dbt v2 is installed, it outputs a single line (such as dbt 2.0.9) with no Core or Plugins block. If dbt-core and dbt-duckdb appear, the environment runs v1. When connected, dbt debug reports the adapter as duckdb (remote).
Contract
Inputs: dbt project, profiles.yml, DuckDB driver, target storage
Outputs: models, tests, target artifacts, warehouse file or lake
Invariants: dbt v2 binary, system driver build, storage version, one writer
Failure: a driver that cannot open the file, a missing extension, a second writer
Proof: version query, storage tag, dbt build, lock checkProve the stack
Before modifying project code, prove the binary and driver stack:
- Run
dbt --version; the output must be a single 2.x line. - Run
dbt debug; the output must reportduckdb (remote). - Run
dbt show --inline "select version()"to verify the engine version. - If the reported engine is not 2.0, run
dbc install duckdbto install the system driver. - Inspect
tags['storage_version']via DuckDB CLI, never via dbt.
On first invocation, dbt v2 downloads a bundled ADBC driver. At dbt 2.0.9, this bundled driver reports DuckDB 1.5.4, writes storage 64 (v1.0.0+), and fails when reading storage 69:
IO Error: Trying to read a database file with version number 999, but we can only read versions between 64 and 68.The vendor docs say the bundled driver cannot load extensions. At dbt 2.0.9 it loaded httpfs, spatial, fts, vss, and ducklake in a probe. Do not rely on that; install the system driver for 2.0-only features.
When reading a 2.0 file, DuckDB 1.5.5 prints raw header number 999; 1.5.6 prints 69. Do not interpret 999 as the storage version. When dbc install duckdb installs the system driver, dbt returns v2.0.0, opens storage 69, and reports tags['storage_version'] as v2.0.0+. Always verify the active driver with the version query. Running pip install duckdb==2.0.0 does not change the driver dbt uses. STORAGE_VERSION is an ATTACH option, not a dbt profile key; setting storage_compatibility_version in a dbt profile cannot create a pre-2.0 file.
Profile
analytics:
target: dev
outputs:
dev:
type: duckdb
path: ./warehouse.duckdb
schema: main
threads: 1
extensions: [httpfs, parquet]
settings:
memory_limit: 4GB
attach:
- path: ./other.sqlite
type: sqlite
read_only: true
secrets:
- type: s3
provider: credential_chainIn profiles.yml, set schema: main explicitly. Without explicit schema, hook compilation renders this as <database>.public.<model> while the model builds in main.
For runtime settings, settings applies DuckDB configuration after attachment. For external data, attach mounts duckdb, sqlite, or postgres databases using the filename basename as the alias. For cloud authentication, secrets configures __dbt_secret_N entries in duckdb_secrets(). When migrating from v1, remove plugins and filesystems. When an external model omits location, external_root defines its directory prefix. See references/project.md for full profile options.
Models
| Materialization | Status | Notes |
table, view, incremental, ephemeral | Supported | Standard SQL models |
seed, snapshot | Supported | CSV fixtures and slowly changing dimensions |
external | Supported | Single Parquet/CSV file at location (no partition_by) |
materialized_view | Unimplemented | Replaced by table plus scheduled refresh |
| Python model | Unsupported | Delegated to duckdb-python |
When writing external models, location must name a single target file, not a directory, and its parent directory must exist. partition_by is not supported on external models; use partitioned_by on DuckLake table or incremental models. When executing transformations, run dbt build rather than dbt run; dbt build executes seeds, models, and tests as one unit. To inspect test failures, pass --store-failures to write audit rows to main_dbt_test__audit.<test_name>. If enforcing model contracts, define explicit data_type on every column in YAML.
Incremental models
| Strategy | Required | Rerun behavior | Failure mode |
append | None | Inserts all source rows | Duplicates rows on rerun |
delete+insert | unique_key | Deletes matching keys, inserts source | Silently appends if unique_key is omitted |
merge | unique_key | MERGE ... UPDATE BY NAME INSERT BY NAME | Emits ON (FALSE) and appends without key |
microbatch | event_time, begin, batch_size | Filters inputs by event window | Warns if upstream ref lacks event_time |
If duplicate source keys match a single target row during merge, the query aborts:
MERGE INTO command cannot affect the same target row more than once.Deduplicate incoming rows prior to merge, or select delete+insert. When verifying model reproducibility, run dbt build --full-refresh to rebuild the target table from scratch. An incremental model is not a trigger-maintained view; see duckdb-sql for dynamic materializations.
Hooks and search indexes
Because a dbt table rebuild drops associated FTS and HNSW indexes, recreate them in a post_hook:
{{ config(
materialized='table',
post_hook="PRAGMA create_fts_index('" ~ this ~ "', 'id', 'body', overwrite=1)"
) }}When updating incremental models, note that DuckDB FTS triggers capture INSERT and DELETE, but not UPDATE. If records update in place, rebuild the search index in a post-hook or execute delete+insert. See duckdb-search for index freshness and vector metric matching.
Orchestration
If running on distributed workers, pin the pipeline to a single local worker with a persistent volume, or persist storage to S3, Parquet, or DuckLake; a new node will see an empty filesystem.
While multiple threads within one dbt process safely write to one DuckDB file, multiple concurrent processes cannot:
IO Error: Could not set lock on file "...": Conflicting lock is held in ... (PID ...)Orchestrate via Airflow, Dagster, or cron using a single dbt build invocation. Never run concurrent writers against the same database file, and do not separate dbt run and dbt test.
Catalogs
In dbt v2, catalogs.yml with the v2 specification is active by default; flags: use_catalogs_v2: true is redundant and only set to false to revert to legacy catalogs. When a model specifies catalog_name, declare that catalog in catalogs.yml.
To attach a DuckLake catalog, configure the profile with path: "ducklake:my_lake.ddb". Because a local .duckdb catalog allows only one writer, shared multi-writer deployments require PostgreSQL or READ_ONLY processes. Consult duckdb-lakehouse before architectural selection.
Move from v1
- Record
dbt --version,dbt-duckdbversion, DuckDB engine build, and database storage tag. - Install dbt v2 in an isolated environment beside the existing project without removing v1.
- Run
dbc install duckdbif the project uses DuckDB 2.0 files or extensions. - Copy
profiles.yml, setschema: mainexplicitly, and removeplugins,filesystems, and v1 external keys. - Execute
dbt debug,dbt show --inline "select version()", anddbt build. - If older readers must open output files, pin storage using DuckDB CLI
ATTACH ... (STORAGE_VERSION 'v1.5.6')andCOPY FROM DATABASE; dbt profiles expose no storage version flag. - Keep the v1 environment until a complete
dbt buildpasses models and tests.
Verify feature parity: Python models and materialized views are not implemented; external models write a single file and ignore partition_by. Seeds and snapshots remain fully supported.
Stop rules
- Do not call a
dbt-duckdbinstall a dbt v2 install. - Do not read
dbt --versionas an adapter list; v2 prints one line. - Do not point a 1.5.4 bundled driver at a storage-69 file.
- Do not claim a profile key controls
STORAGE_VERSION; there is none. - Do not use
mergeordelete+insertwithoutunique_key. - Do not run two writers against one local file.
- Do not put a local warehouse on an ephemeral worker.
- Do not rebuild a model with a search index without rebuilding the index.
- Do not use
--compute inlineorsidecarwith DuckDB; it falls back with a warning and breaks ad-hocduckdb_*queries.
Verify
dbt --version
dbt debug
dbt show --inline "select version()"
dbt buildConfirm that the version query returns the intended DuckDB build, dbt debug connects, and dbt build finishes with zero failed models and tests. Then verify file storage:
duckdb -no-agent -json warehouse.duckdb \
-c "SELECT tags['storage_version'] AS v FROM duckdb_databases() WHERE database_name = current_database();"The tag must match the readers that open the file: v2.0.0+ for DuckDB 2.0, or v1.5.0+ for a file pinned to a 1.5.6 reader.
References
- dbt DuckDB setup owns the profile and
extensionsfield. - dbt v2 upgrade owns the package split.
- dbt v2 release owns the version boundary.
- dbt-duckdb owns the v1 adapter.
- DuckDB dbt announcement owns the built-in adapter and driver caveat.
- dbc owns the driver install.
- references/project.md has profile keys, materialization matrices, exact error strings, and migration details.
- Read
duckdb-lakehousefor catalog selection,duckdb-searchfor index freshness, andduckdb-migratefor storage pins.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

