Preview Support for DuckDB is Now Available in RepoDB

We are excited to announce the preview release of DuckDB support for RepoDB. It brings our hybrid ORM’s fluent CRUD, batch, raw-SQL and Bulk Operations to DuckDB.

Why DuckDB?

DuckDB is an embedded, in-process analytical database, often described as “SQLite for analytics”. It runs inside your application with no server to install. It uses a columnar engine that handles large aggregations, joins and scans quickly. More .NET teams now use it for local analytics, data pipelines, ETL staging and reporting.

Many of these teams are still working with the raw ADO.NET API: hand-written SQL, manual parameter binding, and loops over DbDataReader. We built this provider to remove that work.

How RepoDB helps

  • Less plumbing. You get typed entities, expression-based queries and automatic mapping, and you can still drop down to raw SQL whenever you need to.
  • Fast bulk loading. DuckDB is often used to load large datasets. Our Bulk Operations use DuckDB.NET’s native DuckDBAppender rather than inserting row by row.
  • Driver quirks already handled. DuckDB.NET returns TIME, DATE and BLOB values as driver-specific types. Built-in property handlers map them to TimeSpan, DateTime and byte[]. Identity columns are emulated with sequences and read back through RETURNING.
  • One API across databases. You use the same programming model as our SQL Server, PostgreSQL, MySQL, SQLite, Oracle, DB2, MariaDB, Firebird, ClickHouse, Vertica, SAP HANA and EnterpriseDB extensions.

The integration suites run against a real in-process DuckDB with no containers. Currently, 692 core tests and 590 Bulk Operations tests are passing.

Getting started

Install the packages:

> Install-Package RepoDb.DuckDb -Version 0.0.1-alpha
> Install-Package RepoDb.DuckDb.BulkOperations -Version 0.0.1-alpha

Initialize it once at startup:

GlobalConfiguration
    .Setup()
    .UseDuckDb();

CRUD

Insert

using var connection = new DuckDBConnection("Data Source=analytics.duckdb");
var person = new Person { Name = "John Doe", Age = 30, CreatedDateUtc = DateTime.UtcNow };
var id = connection.Insert(person);

Query

using var connection = new DuckDBConnection("Data Source=analytics.duckdb");
var person = connection.Query<Person>(e => e.Id == 10045).FirstOrDefault();

Update

using var connection = new DuckDBConnection("Data Source=analytics.duckdb");
var person = connection.Query<Person>(e => e.Id == 10045).FirstOrDefault();
person.Age = 31;
var updatedRows = connection.Update(person);

Merge

using var connection = new DuckDBConnection("Data Source=analytics.duckdb");
var person = new Person { Id = 10045, Name = "John Doe", Age = 32, CreatedDateUtc = DateTime.UtcNow };
var id = connection.Merge(person);

Delete

using var connection = new DuckDBConnection("Data Source=analytics.duckdb");
var deletedRows = connection.Delete<Person>(10045);

Batch Operations

The InsertAll, UpdateAll, MergeAll and DeleteAll operations send multiple rows per round-trip. The number of rows per round-trip is controlled by batchSize.

InsertAll

The generated identities are set back on the entities.

using var connection = new DuckDBConnection("Data Source=analytics.duckdb");
var people = GetPeople(1000);
var insertedRows = connection.InsertAll(people, batchSize: 100);

UpdateAll

using var connection = new DuckDBConnection("Data Source=analytics.duckdb");
var people = connection.Query<Person>(e => e.Age < 18).AsList();
people.ForEach(p => p.Age += 1);
var updatedRows = connection.UpdateAll(people, batchSize: 100);

MergeAll

using var connection = new DuckDBConnection("Data Source=analytics.duckdb");
var people = GetPeople(1000);
var mergedRows = connection.MergeAll(people, batchSize: 100);

DeleteAll

using var connection = new DuckDBConnection("Data Source=analytics.duckdb");
var people = connection.Query<Person>(e => e.Age > 100);
var deletedRows = connection.DeleteAll(people);

Bulk Operations

Bulk operations come from RepoDb.DuckDb.BulkOperations. They load rows through DuckDB’s native appender, then apply the changes with a single set-based statement.

BulkInsert

Use ReturnIdentity to get the generated identities back on the entities.

using var connection = new DuckDBConnection("Data Source=analytics.duckdb");
var people = GetPeople(100000);
var insertedRows = connection.BulkInsert(people,
    identityBehavior: DuckDbBulkImportIdentityBehavior.ReturnIdentity);

BulkUpdate

using var connection = new DuckDBConnection("Data Source=analytics.duckdb");
var people = GetPeopleToUpdate();
var updatedRows = connection.BulkUpdate(people);

BulkMerge

using var connection = new DuckDBConnection("Data Source=analytics.duckdb");
var people = GetPeopleToMerge();
var mergedRows = connection.BulkMerge(people, qualifiers: e => new { e.Name });

BulkDelete

using var connection = new DuckDBConnection("Data Source=analytics.duckdb");
var people = GetPeopleToDelete();
var deletedRows = connection.BulkDelete(people);

BulkDeleteByKey

using var connection = new DuckDBConnection("Data Source=analytics.duckdb");
var deletedRows = connection.BulkDeleteByKey("Person", new object[] { 10045, 10046, 10047 });

Every operation also has an Async counterpart. See the DuckDB Bulk Operations page for the details.

A preview, not a final release

RepoDb.DuckDb and RepoDb.DuckDb.BulkOperations are preview packages at v0.0.1-alpha, and their APIs and behavior may change before a stable release. Some known constraints apply. INTERVAL values with month or year parts are not supported, because of a driver limitation. Also, the async bulk methods currently run synchronously underneath, since DuckDBAppender has no async API. The limitations page lists the rest.

We would love to hear your feedback as you try it out. It directly shapes what we prioritize on the way to general availability.


~ Conceptualized by me. Reviewed and checked by AI. Refined and gatekept by me. ~

Please support us

Give a ⭐ to our Github repository | Follow me at X / Twitter | Connect with us at our official Teams Channel
Apache License 2.0 — Copyright © 2026 by Michael Camara Pendon / Create a Request