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. 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 (incl. append_if_unchanged), 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.

How it works

Two engines, split cleanly: DuckDB runs every query and reads Delta through delta_scan views, delta-rs handles every write, an Arrow C-stream bridges them, and dbt orchestrates on top.

duckrun architecture: DuckDB executes SQL and reads Delta via delta_scan; an Arrow C-stream bridges to delta-rs, which handles every write and commits against the read version (OCC); dbt orchestrates on top

Writes are snapshot-pinned: the read is fixed at delta_scan(…, version => N) and the write commits against N, so a concurrent commit is rejected with CommitFailedError instead of silently overwriting a lost update.

Two writers race on one table: Writer A reads v5 and computes; Writer B commits v6 in between; A's commit against v5 is rejected with CommitFailedError instead of silently overwriting B

More on the design: Design document · Snapshot isolation.

Docs

Browse the rendered docs site at djouallah.github.io/duckrun — or read the markdown here:

Doc What's in it
Connection API The duckrun.connect() notebook API + examples.
API reference The exact public method contract, introspected from the code.
dbt adapter Profiles, materializations, incremental strategies, sources, maintenance, limitations.
Design document Why delta-rs (not DuckDB's native Delta writer), why Delta (not Iceberg), why a separate adapter.
Snapshot isolation How a read-modify-write is fenced to the version you read, and how it compares to delta-rs/Spark/SQL Server.
dbt adapter conformance Official dbt-tests-adapter results, regenerated on every push to main.
Incremental MERGE benchmark ~60M-row TPCH merge / append / overwrite scorecard — the release gate.

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

duckrun-0.4.19.tar.gz (175.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

duckrun-0.4.19-py3-none-any.whl (186.3 kB view details)

Uploaded Python 3

File details

Details for the file duckrun-0.4.19.tar.gz.

File metadata

  • Download URL: duckrun-0.4.19.tar.gz
  • Upload date:
  • Size: 175.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for duckrun-0.4.19.tar.gz
Algorithm Hash digest
SHA256 c3abcd80e6dfca32910ff3eabca34dfb40a3503ee4843637646bc9293ef9d5bc
MD5 cfd392f46ed90662096c94db4aeb6ff4
BLAKE2b-256 e8c5e86c4d40093aee3f80824eec499d152dbebe384dad4aaa007407b323070c

See more details on using hashes here.

Provenance

The following attestation bundles were made for duckrun-0.4.19.tar.gz:

Publisher: publish.yml on djouallah/duckrun

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file duckrun-0.4.19-py3-none-any.whl.

File metadata

  • Download URL: duckrun-0.4.19-py3-none-any.whl
  • Upload date:
  • Size: 186.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for duckrun-0.4.19-py3-none-any.whl
Algorithm Hash digest
SHA256 3fed013569e1f9842f0b938f73850b703c7c6f28bc0e7621d1173cc63d8a0679
MD5 f320b005088a5574f1b3cc5edbdc5d2a
BLAKE2b-256 794f3f874e6795ef3a8e4055e6c4b70b3096427b0643ab73e2cace24a1c8598f

See more details on using hashes here.

Provenance

The following attestation bundles were made for duckrun-0.4.19-py3-none-any.whl:

Publisher: publish.yml on djouallah/duckrun

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page