Preview Support for ClickHouse is Now Available in RepoDB
Published:
We are excited to announce the preview release of ClickHouse support for RepoDB — bringing our hybrid ORM’s fluent CRUD, raw-SQL, and Bulk Operations capabilities to ClickHouse for the first time, right out of the gate. This follows the 1,701 passing integration tests we shared a few days ago — that milestone is now a shipped package.

What’s in this preview?
The new RepoDb.ClickHouse package brings the RepoDB experience to ClickHouse, built on top of the official ClickHouse.Driver ADO.NET provider:
- Full CRUD operations — Insert, Query, Update, Delete, and Merge
- Raw-SQL operations — ExecuteQuery, ExecuteNonQuery, ExecuteScalar, and ExecuteReader, for when you need full control over the statement being sent to the server
- Bulk operations, via
RepoDb.ClickHouse.BulkOperations— BulkInsert, BulkUpdate, BulkDelete, BulkDeleteByKey, and BulkMerge, built on ClickHouse’s own native binary insert protocol for high-throughput loads
It follows the same programming model you already use with our SQL Server, PostgreSQL, MySQL, SQLite, Oracle, DB2, MariaDB, and Firebird extensions — the same fluent API, the same lightweight philosophy, now targeting ClickHouse.
Why ClickHouse?
ClickHouse has become one of the default choices for columnar, OLAP-style analytics workloads — high-ingest, aggregate-heavy use cases where RepoDB’s Bulk Operations already shine on other providers. It’s also been one of the most requested providers from the community. This preview closes that gap, so teams running analytics on ClickHouse can get the same fast, hybrid data-access experience RepoDB is known for elsewhere.
ClickHouse isn’t a typical RDBMS — a few things to know up front
ClickHouse is a columnar OLAP engine, not a transactional row-store, and that shapes how a few operations behave compared to SQL Server, PostgreSQL, or MariaDB:
- No identity/auto-increment columns. ClickHouse has no built-in mechanism to generate a primary key server-side, so your application is responsible for assigning IDs before calling
Insert,InsertAll, orBulkInsert. Mergecompiles to a plainINSERT. ClickHouse has no nativeUPSERT/MERGEstatement, so Merge and BulkMerge issue anINSERTby default — deduplication is left to your table engine (e.g.ReplacingMergeTree) rather than done at write time.UpdateandDeleteare asynchronous mutations. ClickHouse appliesALTER TABLE ... UPDATE/DELETEin the background rather than in-place, synchronously. If you need a call to block until the mutation has actually finished, opt in at startup:GlobalConfiguration .Setup() .UseClickHouse(isWaitForMutationsEnabled: true);- The connection string needs
UseCustomDecimals=false. Without it,Decimalcolumns won’t map correctly throughClickHouse.Driver.
None of this is a RepoDB limitation — it’s ClickHouse’s own execution model, and the provider is built to work with it rather than paper over it.
Getting started
Install the packages:
> Install-Package RepoDb.ClickHouse -Version 0.0.1-alpha1
> Install-Package RepoDb.ClickHouse.BulkOperations -Version 0.0.1-alpha1
Initialize it once at startup:
GlobalConfiguration
.Setup()
.UseClickHouse();
Basic CRUD
var connectionString =
"Host=127.0.0.1;Port=8123;Username=default;Password=YourPassword;Database=RepoDb;Protocol=http;UseCustomDecimals=false;";
using (var connection = new ClickHouseConnection(connectionString))
{
// Insert (Id is assigned by the caller — ClickHouse has no identity column)
var person = new Person { Id = 1, Name = "John Doe", Age = 30 };
connection.Insert(person);
// Query
var queriedPerson = connection.Query<Person>(e => e.Id == 1).FirstOrDefault();
// Update (an async mutation under the hood)
queriedPerson.Age = 31;
var updatedRows = connection.Update(queriedPerson);
// Delete
var deletedRows = connection.Delete<Person>(1);
// Merge (compiles to an INSERT)
var mergedPerson = new Person { Id = 2, Name = "Jane Doe", Age = 28 };
connection.Merge(mergedPerson);
}
Raw-SQL
using (var connection = new ClickHouseConnection(connectionString))
{
var people = connection.ExecuteQuery<Person>("SELECT * FROM Person WHERE Age >= @Age;",
new { Age = 18 });
var affectedRows = connection.ExecuteNonQuery("ALTER TABLE Person UPDATE Age = @Age WHERE Id = @Id;",
new { Age = 32, Id = 1 });
var count = connection.ExecuteScalar<ulong>("SELECT COUNT(*) FROM Person;");
}
Bulk Operations
using (var connection = new ClickHouseConnection(connectionString))
{
var people = GetPeopleToInsert();
var insertedRows = connection.BulkInsert(people);
var peopleToMerge = GetPeopleToMerge();
var mergedRows = connection.BulkMerge(peopleToMerge);
var keysToDelete = new long[] { 1, 2, 3 };
var deletedByKeyRows = connection.BulkDeleteByKey<Person>(keysToDelete);
}
A preview, not a final release
As a preview package at v0.0.1-alpha1, RepoDb.ClickHouse (and its Bulk Operations counterpart) is still maturing — APIs and behavior, including the mutation semantics described above, may change before a stable release ships. 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
