Preview Support for ClickHouse is Now Available in RepoDB

4 minute read

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:

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, or BulkInsert.
  • Merge compiles to a plain INSERT. ClickHouse has no native UPSERT/MERGE statement, so Merge and BulkMerge issue an INSERT by default — deduplication is left to your table engine (e.g. ReplacingMergeTree) rather than done at write time.
  • Update and Delete are asynchronous mutations. ClickHouse applies ALTER TABLE ... UPDATE/DELETE in 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, Decimal columns won’t map correctly through ClickHouse.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