Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/nimdeveloper/better-duck/llms.txt

Use this file to discover all available pages before exploring further.

better-duck-diesel is a full Diesel 2.3 backend for DuckDB. It implements the Diesel Connection trait — including SimpleConnection, LoadConnection, AnsiTransactionManager, and migration support — so your existing table! macro definitions, query DSL chains, and migration files work against DuckDB without modification. Both in-memory and on-disk databases are supported out of the box.
better-duck-diesel is currently in beta. The API is settling and breaking changes before 1.0 are possible. Pin the exact pre-release version in your Cargo.toml and check the changelog before upgrading.

Adding the Dependency

Add both crates to your Cargo.toml. Because these are pre-release versions, Cargo’s default "0.1" shorthand will not resolve them — pin the exact version as shown below.
[dependencies]
better-duck-core   = "0.1.0-beta.4"
better-duck-diesel = "0.1.0-beta.4"
diesel             = { version = "2.3", features = ["r2d2"] }  # r2d2 optional
Enable optional features on better-duck-diesel as needed:
[dependencies.better-duck-diesel]
version  = "0.1.0-beta.4"
features = ["chrono", "r2d2"]   # chrono date/time; r2d2 pool support

Connecting

DuckDbConnection implements diesel::Connection, so you open a connection with the standard Connection::establish entry-point. Three URL forms are accepted:
use better_duck_diesel::DuckDbConnection;
use diesel::prelude::*;

// Each call produces an independent, empty in-memory database.
let mut conn = DuckDbConnection::establish(":memory:")?;

Creating Tables

DDL statements are executed through the SimpleConnection::batch_execute method, which accepts any SQL string — including multi-statement batches separated by semicolons. You must bring the SimpleConnection trait into scope explicitly.
use better_duck_diesel::DuckDbConnection;
use diesel::{connection::SimpleConnection, prelude::*};

let mut conn = DuckDbConnection::establish(":memory:")?;

conn.batch_execute(
    "CREATE TABLE products (
        id    INTEGER PRIMARY KEY,
        name  VARCHAR NOT NULL,
        price DOUBLE  NOT NULL
    )",
)?;
batch_execute is also the right tool for CREATE TYPE, CREATE SEQUENCE, DROP TABLE, and any other DDL that does not return rows.

Connection Pooling

The r2d2 Cargo feature unlocks two complementary pooling strategies. Both use r2d2::Pool::builder() — they differ in how each pooled connection relates to the underlying DuckDB database file.
use better_duck_diesel::pool::SharedDuckDbConnectionManager;
use diesel::r2d2::Pool;

// All connections in the pool share one Database handle.
// Essential for in-memory databases where each independent
// connection would otherwise see an empty database.
let manager = SharedDuckDbConnectionManager::memory()?;
let pool    = Pool::builder().max_size(8).build(manager)?;

let mut conn = pool.get()?;
SharedDuckDbConnectionManager can also be backed by a file:
use better_duck_diesel::pool::SharedDuckDbConnectionManager;
use diesel::r2d2::Pool;

let manager = SharedDuckDbConnectionManager::file("/path/to/db.duckdb")?;
let pool    = Pool::builder().max_size(4).build(manager)?;

From Core Connection

If you already have a better_duck_core::connection::Connection — for example, one obtained from a better_duck_core::database::Database — you can wrap it as a Diesel connection without re-opening the file:
use better_duck_core::database::Database;
use better_duck_diesel::DuckDbConnection;

let db   = Database::open_in_memory()?;
let core = db.connect()?;

// Wrap the core connection in a full Diesel DuckDbConnection.
let mut conn = DuckDbConnection::from_core(core);
This is how SharedDuckDbConnectionManager works internally, and it is the only way to make multiple Diesel connections share a single in-memory database without going through the pool API.

Build docs developers (and LLMs) love