Disclaimer: This is a personal project. It is not affiliated with, endorsed by, or supported by any employer or vendor. No warranty — use it at your own risk.
duckrun runs SQL in DuckDB and reads/writes Delta Lake via delta-rs — locally or on OneLake / S3 / GCS / ADLS. It's just glue: DuckDB executes · delta-rs materializes · Arrow bridges · dbt orchestrates. Two ways to use it:
connect()— a notebook helper to query and write Delta straight from SQL (this page);- a dbt adapter that materializes models as Delta tables.
Concurrent writers are first-class: every write is snapshot-pinned and fails loud rather than silently interleaving.
Install
In a Microsoft Fabric notebook, upgrade and restart the kernel (duckrun needs duckdb ≥ 1.5.4,
which is newer than the bundled stable build; it fails loud at connect() otherwise):
!pip install duckrun --upgrade
notebookutils.session.restartPython()
Quickstart — OneLake in a notebook
import duckrun
# Read-only by default — explore a lakehouse safely, no chance of an accidental write.
# Use the workspace + lakehouse GUIDs (friendly names hit an upstream OneLake read bug for now).
conn = duckrun.connect("abfss://<workspace_id>@onelake.dfs.fabric.microsoft.com/<lakehouse_id>/Tables/dbo")
conn.sql("SHOW TABLES").show()
conn.sql("select status, count(*) from orders group by status").show()
conn.sql("select * from orders").df() # native DuckDB relation → pandas (.arrow(), .pl() too)
# Time travel: read an older version with delta_scan(…, version => N)
conn.sql("select * from delta_scan('.../Tables/dbo/orders', version => 0)").show()
Need to write? Opt in with read_only=False — everything is SQL:
conn = duckrun.connect("abfss://…/Tables/dbo", read_only=False)
# write Delta straight from SQL — CREATE TABLE AS routes to delta-rs
conn.sql("CREATE OR REPLACE TABLE clean_orders AS SELECT * FROM orders WHERE amount > 0")
# raw DML routes to delta-rs (insert / update / delete / alter / drop)
conn.sql("delete from clean_orders where amount = 0")
# upsert — snapshot-pinned automatically, nothing extra to pass
conn.sql("""
MERGE INTO clean_orders t USING updates s ON t.id = s.id
WHEN MATCHED THEN UPDATE SET *
WHEN NOT MATCHED THEN INSERT *
""")
conn.close()
Multiple catalogs — attach more lakehouses and read/join across them by three-part name. In
Fabric a Warehouse is just a write-locked Lakehouse, so attach it read_only=True next to a writable
one:
conn.attach("abfss://…/warehouse.Warehouse/Tables", name="warehouse", read_only=True)
conn.attach("/data/reference", name="local")
conn.sql("select * from warehouse.mart.facts f join local.dbo.lookup l on l.id = f.id").show()
Works the same against a local path, s3://, gs://, or az://. Full method map:
Connection API · API reference ·
live multi-catalog demo.
dbt adapter
duckrun is also a dbt adapter — a thin wrapper around
dbt-duckdb that adds Delta-backed table / incremental
materializations (everything else dbt-duckdb gives you is inherited). Point a profile at a lakehouse
and dbt run:
# ~/.dbt/profiles.yml
my_project:
outputs:
dev:
type: duckrun
root_path: "abfss://<workspace_id>@onelake.dfs.fabric.microsoft.com/<lakehouse_id>/Tables"
Multiple lakehouses in one project — declare extra write roots as named catalogs: and send a
model to one with the standard dbt +database: <alias> config (e.g. a Bronze/Silver/Gold medallion
across three Fabric Lakehouses). ref() and joins resolve across them:
dev:
type: duckrun
root_path: "abfss://ws@onelake.dfs.fabric.microsoft.com/LH_Silver.Lakehouse/Tables" # default
catalogs:
lh_bronze: { root_path: "abfss://ws@onelake.dfs.fabric.microsoft.com/LH_Bronze.Lakehouse/Tables" }
lh_gold: { root_path: "abfss://ws@onelake.dfs.fabric.microsoft.com/LH_Gold.Lakehouse/Tables" }
-- models/bronze/raw_events.sql → lands in LH_Bronze
{{ config(materialized='incremental', database='lh_bronze', unique_key='id') }}
select ...
Profiles, materializations, incremental strategies (merge, insert, append, delete+insert, microbatch), sources, and automatic compaction/vacuum are all in docs/dbt-adapter.md.
See it on real projects: aemo and coffee are
runnable starters, and parity_tests/ runs real type: duckdb projects (jaffle_shop,
sde, MRR, TechFlow, Tuva) unchanged on duckrun and diffs the output against dbt-duckdb.
Building with an AI assistant
duckrun ships a guide so AI coding assistants get the adapter's defaults right (several differ from other dbt adapters). For Claude Code:
/plugin marketplace add djouallah/duckrun
/plugin install duckrun-projects@duckrun
Other assistants read the AGENTS.md at the repo root, which points to the full guide.
None of this is required to use duckrun.
Docs
Everything else — architecture, snapshot isolation, conformance results, benchmarks — lives on the docs site: djouallah.github.io/duckrun.
License
MIT
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file duckrun-0.4.37.tar.gz.
File metadata
- Download URL: duckrun-0.4.37.tar.gz
- Upload date:
- Size: 236.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ad3de58da962e1cd79040e8d1075f9723fb3304481500d78c69254062a7b4b29
|
|
| MD5 |
e1192408454d60e520a3bb35d7508f4c
|
|
| BLAKE2b-256 |
0e3c18abca15e80f3bfa57ecc135db0d2135358daf8dd2380853c9e1de0da189
|
Provenance
The following attestation bundles were made for duckrun-0.4.37.tar.gz:
Publisher:
publish.yml on djouallah/duckrun
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
duckrun-0.4.37.tar.gz -
Subject digest:
ad3de58da962e1cd79040e8d1075f9723fb3304481500d78c69254062a7b4b29 - Sigstore transparency entry: 2297211715
- Sigstore integration time:
-
Permalink:
djouallah/duckrun@af9e80117eb2a1704b8bcc66ab545f037750bb64 -
Branch / Tag:
refs/tags/v0.4.37 - Owner: https://github.com/djouallah
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@af9e80117eb2a1704b8bcc66ab545f037750bb64 -
Trigger Event:
push
-
Statement type:
File details
Details for the file duckrun-0.4.37-py3-none-any.whl.
File metadata
- Download URL: duckrun-0.4.37-py3-none-any.whl
- Upload date:
- Size: 249.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
cdcbc9b15c0f3a74800974d2696450ee4a19f5b4813a0e59cae5b1a091cbec97
|
|
| MD5 |
46398515905d05c3ceabf28b226f8ff2
|
|
| BLAKE2b-256 |
82a3374d4c947142c797d4b2088cda9f3e659252c6ee4a858b6579a156675577
|
Provenance
The following attestation bundles were made for duckrun-0.4.37-py3-none-any.whl:
Publisher:
publish.yml on djouallah/duckrun
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
duckrun-0.4.37-py3-none-any.whl -
Subject digest:
cdcbc9b15c0f3a74800974d2696450ee4a19f5b4813a0e59cae5b1a091cbec97 - Sigstore transparency entry: 2297211823
- Sigstore integration time:
-
Permalink:
djouallah/duckrun@af9e80117eb2a1704b8bcc66ab545f037750bb64 -
Branch / Tag:
refs/tags/v0.4.37 - Owner: https://github.com/djouallah
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@af9e80117eb2a1704b8bcc66ab545f037750bb64 -
Trigger Event:
push
-
Statement type: