Preview Support for CockroachDB is Now Available in RepoDB
We are excited to announce the preview release of CockroachDB support for RepoDB. It brings our hybrid ORM’s fluent CRUD, batch, raw-SQL and Bulk Operations to CockroachDB.
Why CockroachDB?
CockroachDB is a distributed SQL database built for resilience and horizontal scale. It replicates data across nodes, regions and clouds, survives node failures without downtime, and keeps transactions strongly consistent. It speaks the PostgreSQL wire protocol, so it feels familiar, but it is a different engine with its own SQL dialect and behavior.
That difference is the reason for a dedicated provider. PostgreSQL tooling works mostly with CockroachDB, and the places where it doesn’t (identity columns, INT sizes, temporary tables, upserts) are exactly where data-access code breaks. We built this provider so .NET teams get the RepoDB experience on CockroachDB without relying on PostgreSQL compatibility.
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.
- SQL written for CockroachDB. Inserts read back identities with
RETURNINGin the same round-trip. Merges compile toINSERT ... ON CONFLICT ... DO UPDATE, and paging usesLIMIT/OFFSET. - Fast bulk loading. Bulk Operations stream rows through a binary
COPY-protocol writer rather than inserting row by row. Values are converted to the destination column types first. For example, anintproperty is sent as CockroachDB’s 64-bitINT. - 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, EnterpriseDB and DuckDB extensions.
Both packages are built on RepoDb.Connector.CockroachDb, the Npgsql-based CockroachDB connector from our RepoDB Connectors project. It supplies CockroachDbConnection and CockroachDbBulkCopy.
Getting started
Install the packages:
> Install-Package RepoDb.CockroachDb -Version 0.0.1-alpha
> Install-Package RepoDb.CockroachDb.BulkOperations -Version 0.0.1-alpha
Initialize it once at startup:
GlobalConfiguration
.Setup()
.UseCockroachDb();
The samples below use this connection string (a local single-node cluster):
var connectionString = "Host=127.0.0.1;Port=26257;Username=root;Database=RepoDb;";
For a complete walkthrough, follow the Get Started with CockroachDB tutorial.
CRUD
Insert
using var connection = new CockroachDbConnection(connectionString);
var person = new Person { Name = "John Doe", Age = 30, CreatedDateUtc = DateTime.UtcNow };
var id = connection.Insert(person);
Query
using var connection = new CockroachDbConnection(connectionString);
var person = connection.Query<Person>(e => e.Id == 10045).FirstOrDefault();
Update
using var connection = new CockroachDbConnection(connectionString);
var person = connection.Query<Person>(e => e.Id == 10045).FirstOrDefault();
person.Age = 31;
var updatedRows = connection.Update(person);
Merge
using var connection = new CockroachDbConnection(connectionString);
// Compiles to INSERT ... ON CONFLICT ... DO UPDATE
var person = new Person { Id = 10045, Name = "John Doe", Age = 32, CreatedDateUtc = DateTime.UtcNow };
var id = connection.Merge(person);
Delete
using var connection = new CockroachDbConnection(connectionString);
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 CockroachDbConnection(connectionString);
var people = GetPeople(1000);
var insertedRows = connection.InsertAll(people, batchSize: 100);
UpdateAll
using var connection = new CockroachDbConnection(connectionString);
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 CockroachDbConnection(connectionString);
var people = GetPeople(1000);
var mergedRows = connection.MergeAll(people, batchSize: 100);
DeleteAll
using var connection = new CockroachDbConnection(connectionString);
var people = connection.Query<Person>(e => e.Age > 100);
var deletedRows = connection.DeleteAll(people);
Bulk Operations
Bulk operations come from RepoDb.CockroachDb.BulkOperations. They load rows through CockroachDbBulkCopy’s binary COPY protocol, 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 CockroachDbConnection(connectionString);
var people = GetPeople(100000);
var insertedRows = connection.BulkInsert(people,
identityBehavior: CockroachDbBulkImportIdentityBehavior.ReturnIdentity);
BulkUpdate
using var connection = new CockroachDbConnection(connectionString);
var people = GetPeopleToUpdate();
var updatedRows = connection.BulkUpdate(people);
BulkMerge
using var connection = new CockroachDbConnection(connectionString);
var people = GetPeopleToMerge();
var mergedRows = connection.BulkMerge(people, qualifiers: e => new { e.Name });
BulkDelete
using var connection = new CockroachDbConnection(connectionString);
var people = GetPeopleToDelete();
var deletedRows = connection.BulkDelete(people);
BulkDeleteByKey
using var connection = new CockroachDbConnection(connectionString);
var deletedRows = connection.BulkDeleteByKey("Person", new object[] { 10045, 10046, 10047 });
Every operation also has an Async counterpart. See the CockroachDB Bulk Operations page for the details.
A preview, not a final release
RepoDb.CockroachDb and RepoDb.CockroachDb.BulkOperations are preview packages at v0.0.1-alpha, and their APIs and behavior may change before a stable release. Both require .NET 8.0 or later, and the connector underneath is itself a prerelease.
One CockroachDB behavior is worth knowing up front. A schema change inside a transaction commits the work that transaction has already done. The bulk merge, update and delete operations create staging tables, so running them inside a transaction commits the earlier statements in it. The limitations page covers this and 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