<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:opsz,wght@14..32,300..700&amp;family=JetBrains+Mono:wght@400;500;600&amp;display=swap" />
Rust · 2026
crates.ioRustDuckDBproc-macroSQL

ducklake-orm

Rust ORM for DuckDB and DuckLake, published on crates.io — derive macros, query builders, pooling, migrations, time travel.

01The problem

DuckDB and DuckLake are great for analytics, but using them from Rust meant hand-written SQL and loosely typed results. I wanted the ergonomics of an ORM without hiding what the database does well.

02What I built

A lightweight Rust ORM for DuckDB, built to make analytical storage feel approachable without hiding the useful parts. The work is about typed boundaries, data ergonomics, and the small API decisions that make a tool pleasant to keep using.

  1. 01Derive macros map structs to tables with zero boilerplate
  2. 02Type-safe filters, order_by, limit, count, fetch_one
  3. 03Pooling, migrations, and DuckLake time travel
  4. 0439 integration tests against a real DuckDB
03Architectural decisions
  1. 01

    Typed errors and discoverable defaults

    Analytical storage is powerful, but power alone does not make a tool pleasant to use on an ordinary workday.

    Engineering choiceTyped errors, defaults you can discover from the API, and migrations inside the library — so a new user can predict what happens next without opening the implementation.
  2. 02

    Know where the abstraction stops

    An ORM that hides everything makes the reader pay its complexity tax.

    Engineering choiceDerive macros and query builders cover the common path — filters, ordering, limits, counts, fetch_one. Beyond that the database speaks for itself, including DuckLake time travel.
05What I learned

The layer under the query: typed boundaries, data ergonomics, and what it takes to make analytical storage feel like a product.