NAME
celeriant is a fast, two-node append-only event store
SYNOPSIS
// write your events to an aggregate
await pool.WriteAsync(key, [event], clientId, expectedVersion: version);
// you can do atomic, cross-aggregate writes with optimistic concurrency control
await pool.WriteAsync(new WriteRequest {
ClientId = clientId,
Writes = new() {
[from] = new() { Events = [withdrawn], ExpectedVersion = fromVersion },
[to] = new() { Events = [deposited], ExpectedVersion = toVersion },
},
});
// per-aggregate reads for read models
await foreach (var batch in pool.ReadAllAsync(key, ReadFilters.From(version)))
foreach (var e in batch.Events)
state = Apply(state, e); PURPOSE FOR EXISTING
There is currently no good, fast, dedicated event store implementation that is open source.
It exists because as a consultant, I see clients fuck up event sourcing over and over again and there needs to be a better primitive for this pattern.
Dev teams reach for Kafka to move events between services, but there is no optimistic concurrency control and no per aggregate reads. State between services gets coupled which is often subtle and the system invariants break in prod.
The popular open source alternative is Marten on Postgres, which needs a background daemon just to hand your async projections the events in order.
Celeriant is not a vibe-coded project. See PROVENANCE.
FEATURE DUMP
The quick TLDR of what Celeriant is and what it isn't.
A server, not embedded
Two node cluster, high availability, requires an S3 compatible object store but only for leadership arbitration. Any event you write is durably stored to disk before acknowledging to the client.
OCC + DCB
An implementation subset of dynamic consistency boundaries. Means you can do atomic writes over multiple aggregates. Optimistic concurrency control to make sure your system rules don't get broken under concurrent writes to aggregates. Limited to aggregates co-located on the same shard.
Exactly-once append
Proper idempotency implementation for clients. Never get duplicate events in your event store for an aggregate. Reference implementation available.
Per aggregate reads and watch API.
Provide an offset position and get the events for an aggregate after that. No out of order events and no gaps in the sequence. Connect to the server via the watch API and get an instant notification when events hit an aggregate.
End to end encryption
Encrypt individual events to adhere to GDPR using crypto shredding techniques. Event log stays immutable, but you stay compliant.
Server-side schema validation
Unlike Kafka, server-side schema validation for events is built in and open source. JSON, Protobuf, avro support.
What it's not
Celeriant doesn't have read projections or a read model. No SQL, no analytical queries. Write side only. Pure, hardcore, CQRS.
PERFORMANCE
The only database that makes the most hardcore AWS i4i instances sweat.
- Connections
- 60,000
- Durable writes / sec
- 1,057,000
- p50
- 48 ms
- p95
- 72 ms
- p99
- 108 ms
- Client Concurrency
- 60,000 durable writes in flight at once, across four load-generating clients. Easily handles 100k connections without breaking.
- Payload
- one "Hello World" event per acknowledged write. No client-side batching
- Hardware
- two AWS i4i.metal data nodes: 64 physical cores each (128 vCPU, two sockets), eight local NVMe drives striped RAID0
- Cost
- $26.33 an hour. scales down to $295 a month and still hold 67,000 durable writes a second at p99 165ms, replicated and mTLS the whole way
- Network
- ap-southeast-2, single availability zone. Expect higher costs and latency for cross-AZ
- Security
- mTLS on client connections and on cluster replication
- Durability
- every write is fdatasync'd to disk on both nodes through Direct I/O, replicated to the follower, and acknowledged only after both succeed
Every latency is end-to-end, including replication and both fsyncs, over mTLS on the client and replication paths. That is encrypted, durable, replicated throughput. Reproduce it yourself for a few dollars.
CONFORMING TO
Apache-2.0. The server runs on Linux. Clients exist for .NET and Rust.
NERDY STUFF
The parts that aren't obvious from the feature list.
S3 conditional writes instead of Raft
No Raft, no Paxos, no ZooKeeper. Leader election is a compare-and-swap on one S3 object, and a leader whose lease expires fences itself. S3 doubles as the backup replica, so losing the follower doesn't stop writes. Nothing is acked until it sits on two storage systems.
kTLS on the io_uring path
Most io_uring databases skip TLS. The rest wrap the stream in userspace and hand back the zero-copy win.
Celeriant handshakes with rustls, then passes the session secrets to the kernel via setsockopt(SOL_TLS). The kernel does the crypto and io_uring never touches ciphertext.
Metablocks grow up, datablocks grow down
Fixed 1024-byte metablocks grow from the top of the WAL file, variable datablocks grow backwards from the bottom, and the file rotates when they meet. Free space is the gap between two cursors. No fragmentation, nothing to manage, every metablock at a predictable offset.
Small batches sit inline in the metablock. One less seek.
Bloom filters over reverse WAL scanning
Every segment carries a 256KB bloom filter of its aggregate keys, so a cold read scanning backwards skips whole segments on one check. Ten million aggregates, and no ten million index entries in RAM.
Connections hand off between cores
A TCP stream belongs to one executor. But a client lands on whichever core accepted it, and its first request may be for an aggregate another shard owns. So the connection moves. Unbound, sent across the mesh channel, rebound on the target core. If the mesh is full the client gets SERVER_BUSY rather than stalling a WAL write.
Glommio couldn't do this. You could route a raw fd, but not after
reading from the stream, and you have to read the request to know where
it goes. Upstreamed as TcpStream::into_accepted, merged June
2026.
Speculate aggressively, roll back safely
Writes hit disk before replication confirms. Every segment carries two cursors, so the write path sees data straight after fsync and OCC stays correct, while readers wait for replication. Nobody reads a write that could still be rolled back.
When replication fails the cursor rewinds, caches clear, and segment headers are physically rewritten back.
Tested by pulling the plug
Speed is measured on AWS. Correctness is measured on two Raspberry Pi 5s, because slow hardware opens races an i4i.metal never will.
Thirty-one scenarios kill processes, sever replication, stop S3, skew both clocks and fill the disk, against a real cluster over SSH, from a seed that replays exactly.
PROVENANCE
Celeriant is not a vibe-coded project. Built by one veteran dev over a period of 3 years.
Opus & Fable are used. Mostly around the boring parts; scaffolding test harnesses, long running autonomous testing and finding bugs. Any production code written by LLMs is done in a sandbox, discarded and re-written by a human. See build-method and human-replay.
Building Celeriant has been a form of artistic expression for me. Painters paint, poets write poems, devs write code.
CONTACT
Celeriant is released under Apache-2.0. The OSS core will be fully functional; no crippled community edition.
The database is new and still somewhat experimental. Try it in non-prod first.
Email me at [email protected] or add me on LinkedIn. Or just grab the code on GitHub and give it a go.