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

duckrun-0.4.35.tar.gz (231.0 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.35-py3-none-any.whl (243.9 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: duckrun-0.4.35.tar.gz
  • Upload date:
  • Size: 231.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for duckrun-0.4.35.tar.gz
Algorithm Hash digest
SHA256 1210002511e5d1e4964c13629439ef9819a1154575c2f1795648297d7f69be55
MD5 982ac2ac6dcf38a5f098ced357154d56
BLAKE2b-256 4aa00d98aa2947c148bcc98711e778c39de29d7911499004ecbc8e9ff90f3656

See more details on using hashes here.

Provenance

The following attestation bundles were made for duckrun-0.4.35.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.35-py3-none-any.whl.

File metadata

  • Download URL: duckrun-0.4.35-py3-none-any.whl
  • Upload date:
  • Size: 243.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for duckrun-0.4.35-py3-none-any.whl
Algorithm Hash digest
SHA256 7b00d6b5df8ec43db70e711c0b7608736d310bc730275e0f7464eba4edb48ab7
MD5 d1c1339799c599026fc0197610ba1656
BLAKE2b-256 ff1c48693988874c7f1cc4fa6b1de199ba52822b5353a993e66ed8f4eb7c0249

See more details on using hashes here.

Provenance

The following attestation bundles were made for duckrun-0.4.35-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