Skip to main content
better-duck-diesel is a third-party Diesel 2.3 backend for DuckDB. It plugs the better-duck-core driver into Diesel’s typed query builder, so you connect, map a schema with table!, and build INSERT/SELECT/UPDATE/DELETE queries as Rust — while still reaching the DuckDB-specific SQL (operators, scalar functions, aggregates, types) that stock Diesel has no equivalent for. DuckDB itself is compiled and embedded through core, so there is no system install and no libduckdb to link against.

What it is

DuckDbConnection is a full Diesel Connection + LoadConnection. That means:
  • conn.transaction(|c| …) and begin_test_transaction work — see Transactions.
  • Prepared-statement caching and instrumentation work.
  • r2d2 pooling works — see Pooling.
  • diesel migration works — the connection implements MigrationConnection, see Schema & Migrations.
  • .inner() / .inner_mut() expose the underlying core Connection for registering UDFs, loading extensions, and running core-only APIs — see Installation & Setup.
This crate’s default feature set is ["decimal"] only. Unlike better-duck-core, chrono is NOT on by default here — turn it on for date/time column support. See Feature flags below.

30-second quickstart

See Installation & Setup for the full connection surface and Schema for mapping tables.

The two SQL surfaces

Diesel core already gives you the portable surface, and it works on DuckDbConnection with no extra imports: =/</>, LIKE, count/sum/avg/min/max, .filter/.order/.limit, joins, insert_into/update/delete, RETURNING, ON CONFLICT. The DuckDB-only surface lives behind one import, brought in alongside Diesel’s prelude:
That prelude adds two operator extension traits (DuckExpressionMethods, DuckTextExpressionMethods) plus a large library of typed free functions and aggregates — all emitting real DuckDB SQL, none requiring sql_query. See the DSL overview for the map of this surface.
Spatial ST_* functions are not in the dsl::* prelude — import them from better_duck_diesel::spatial::* under feature = "spatial". See Spatial.

Feature flags

Verified against crates/better-duck-diesel/Cargo.toml.
There is no bundled feature on this crate (an older README feature table listed one, but Cargo.toml does not define it). DuckDB is embedded through core regardless. The spatial feature carries no extra Rust deps — it only gates the module; the ST_* functions are plain SQL, and ensure_loaded installs/loads the extension at runtime (needs network unless already present).
For the full project-wide feature picture, see feature flags.

When to use the ORM vs raw core

Reach for better-duck-diesel when you want a typed query builder, schema mapping, migrations, or pooling over DuckDB. Drop to better-duck-core whenever you need something below the ORM — the appender for bulk insert, columnar chunks, async, Arrow/Polars interop, or raw parameter binding. Those are not part of the Diesel surface. Because DuckDbConnection::inner_mut() hands you the core Connection, you can mix both in the same program. See Choosing an API.

Sibling crates

better-duck-core

The raw Rust driver: connections, values, appender, columnar chunks, async.

UDF & derive macros

The #[duckdb_*] UDF macros and FromRow/DuckEnum/DuckStruct derives.

DuckDB SQL DSL

DuckDB-only operators, scalar functions, aggregates, and spatial.

Type mapping

Rust ↔ DuckDB type mapping and the values::* binding newtypes.