Skip to main content
duckrun

PyPI Downloads Downloads/month Python License

Disclaimer: This is a personal project. It is not affiliated with, endorsed by, or supported by any employer or vendor.

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()

For the dbt adapter, install the extra instead: pip install "duckrun[dbt]".

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.

Debugging a model

When a model runs but the numbers are wrong, compile it with dbt and get a DuckDB relation back — real types, lazy, read-only. Because the adapter runs DuckDB in-process, dbt only has to compile; duckrun executes. No dbt show JSON round trip, so nothing has to guess a type per column.

from duckrun import dbt_project

p = dbt_project("dbt/", target="dev")

p.show("orders_enriched").filter("customer = 'X'").limit(100)   # pushes into the delta_scan
p.sql("select * from {{ ref('stg_orders') }} where year = 2026")

# run the model one CTE at a time to find where the row count goes wrong
p.ctes("orders_enriched")                        # ['base', 'allocated', 'final']
p.cte("orders_enriched", "allocated").count("*")

More — CTE slicing, which is_incremental() branch you are looking at, ephemeral models, and why the session cannot write — in docs/dbt-debug.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 — their own tests included.

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.

Contributing

Bug reports and PRs are welcome — see CONTRIBUTING.md for the flow (branch, PR, which CI checks actually gate) and the short list of rules.

Docs

Everything else — architecture, snapshot isolation, conformance results, benchmarks — lives on the docs site: djouallah.github.io/duckrun.

License

MIT

Release files for duckrun 0.5.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for duckrun 0.5.0
File Size Uploaded
duckrun-0.5.0.tar.gz 298.7 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for duckrun 0.5.0
File Interpreter ABI Platform
duckrun-0.5.0-py3-none-any.whl Python 3 none any Details

Total release size: 612.1 kB

Release files / duckrun-0.5.0.tar.gz

Download URL duckrun-0.5.0.tar.gz
Size 298.7 kB
Tags Source
SHA-256 checksum
How to use checksums
b1a7b52ef0a67ef076477e00a6f4a56d4851da844e6dd8c5051b8e6b81f16008
BLAKE2b-256 checksum
How to use checksums
0f4c0709de7226fa0b3abd47a3c2b6555be4dff642ebd80914f3bb794011849d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 23, 2026.

Transparency log

Release files / duckrun-0.5.0-py3-none-any.whl

Download URL duckrun-0.5.0-py3-none-any.whl
Size 313.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
766529a3e31967d59697ef0497969b1be295501576d6da272438f2393a9dc157
BLAKE2b-256 checksum
How to use checksums
2914a53034deb4d09e33eb6f556cb98e675f25843ec87916db12cbbd8b112b15
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 23, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.5.0 This release

2 release files

0.4.71

2 release files

0.4.70

2 release files

0.4.69

2 release files

0.4.65

2 release files

0.4.64

2 release files

0.4.61

2 release files

0.4.60

2 release files

0.4.57

2 release files

0.4.56

2 release files

0.4.55

2 release files

0.4.54

2 release files

0.4.53

2 release files

0.4.52

2 release files

0.4.51

2 release files

0.4.50

2 release files

0.4.49

2 release files

0.4.37

2 release files

0.4.36

2 release files

0.4.35

2 release files

0.4.34

2 release files

0.4.32

2 release files

0.4.31

2 release files

0.4.30

2 release files

0.4.29

2 release files

0.4.28

2 release files

0.4.27

2 release files

0.4.26

2 release files

0.4.25

2 release files

0.4.24

2 release files

0.4.23

2 release files

0.4.22

2 release files

0.4.21

2 release files

0.4.20

2 release files

0.4.19

2 release files

0.4.18

2 release files

0.4.17

2 release files

0.4.16

2 release files

0.4.15

2 release files

0.4.1

2 release files

0.4.0

2 release files

0.3.27

2 release files

0.3.26

2 release files

0.3.25

2 release files

0.3.24

2 release files

0.3.23

2 release files

0.3.22

2 release files

0.3.21

2 release files

0.3.20

2 release files

0.3.19

2 release files

0.3.18

2 release files

0.3.17

2 release files

0.3.16

2 release files

0.3.15

2 release files

0.3.14

2 release files

0.3.9

2 release files

0.3.8

2 release files

0.3.7

2 release files

0.3.6

2 release files

0.3.5

2 release files

0.3.4

2 release files

0.3.3

2 release files

0.3.2

2 release files

0.3.1

2 release files

0.3.0

2 release files

0.2.26

2 release files

0.2.25

2 release files

0.2.24

2 release files

0.2.23

2 release files

0.2.21

2 release files

0.2.20

2 release files

0.2.19

2 release files

0.2.15

2 release files

0.2.13

2 release files

0.2.12

2 release files

0.2.11

1 release file

0.2.10

2 release files

0.2.9

2 release files

0.2.7

2 release files

0.2.6

2 release files

0.2.4

2 release files

0.2.3

2 release files

0.2.2

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.1.9

2 release files

0.1.8

2 release files

0.1.7

2 release files

0.1.6

2 release files

0.1.5

2 release files

0.1.4

2 release files

0.1.3

2 release files

0.1.2

2 release files

0.1.1

2 release files

0.0.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page