We can't find the internet
Attempting to reconnect
Something went wrong!
Hang in there while we get back on track
Comparisons
Documentation
ReckonDB vs KurrentDB (EventStoreDB)
KurrentDB, formerly EventStoreDB, is the oldest dedicated event store and the most widely deployed. If you’ve been around event sourcing for a while, you’ve used it or evaluated it. This page is an honest comparison.
The Short Version
| ReckonDB | KurrentDB | |
|---|---|---|
| Primary store | Khepri/Ra (BEAM Raft) | Proprietary leader election |
| License | Apache-2.0 | BSL (commercial beyond limits) |
| gRPC API | ✅ | ✅ |
| HTTP/JSON API | ❌ (planned) | ✅ |
| Secondary indexes | ✅ tags, event type, metadata | ✅ category, event type (25.1+) |
| Filter-based DCB | ✅ | ❌ |
| Multi-stream append (enumerate) | ✅ | ✅ (25.1+) |
| Competing consumers | 🟡 (in development) | ✅ persistent subscriptions |
| CQRS framework | ✅ evoq | ❌ |
| Managed cloud | ❌ | ✅ Kurrent Cloud |
| Erlang/Elixir native | ✅ | 🟡 (client library only) |
| Tamper resistance | ✅ HMAC + hash chain | ❌ |
Where ReckonDB Leads
Filter-based DCB vs stream-enumeration-based multi-append
KurrentDB 25.1 added multi-stream atomic append, you can append to multiple streams in one operation with per-stream expected version checks. They market this as eliminating saga patterns for cross-aggregate consistency. It is a real improvement, and ReckonDB supports the equivalent.
But it is not the DCB pattern.
The difference is in how the consistency boundary is defined:
KurrentDB multi-stream append:
Enumerate the exact streams involved → specify expected version per stream → append atomically
You must know which streams contain the relevant events before you read. If the invariant you’re enforcing spans an open-ended set of streams (e.g., “has anyone else registered this email?”), you cannot enumerate the streams upfront without a side lookup.
ReckonDB DCB:
1. Read all events matching a tag/type filter since global position N
2. Run domain logic on those events
3. Append atomically IF nothing new matched that filter since N
The consistency boundary is a tag filter on the global log position. You don’t
enumerate streams. You ask: “has any event matching {any_of, ["email:alice@acme.com"]}
appeared since position 4201?” The store answers atomically inside a single Raft
log entry, the read context and the conditional write are indivisible.
This distinction matters for real domains:
| Use case | KurrentDB multi-stream | ReckonDB DCB |
|---|---|---|
| Unique username / email | Requires naming convention to map email→stream |
{any_of, ["email:alice"]}, no convention needed |
| Seat reservation for event N | Know the seat streams → works |
{and_,[{event_type,"seat_reserved"},{any_of,["show:42"]}]} |
| Credit limit across N accounts | Must enumerate account streams |
{any_of, ["account:X","account:Y"]} with tag index |
| Rate limit (rolling window) | Hard: window boundary is time-based, not stream-based | Tag + temporal filter |
Secondary indexes: custom depth
KurrentDB 25.1 added indexed reads for category and event type. These are the two most common query shapes, and KurrentDB now does them well (10× faster than system projections, 80% less storage).
ReckonDB indexes three dimensions:
| Index type | ReckonDB | KurrentDB |
|---|---|---|
| Event type | ✅ | ✅ (25.1+) |
| Category / stream prefix | ✅ tags | ✅ (25.1+) |
| Arbitrary tag | ✅ any value at append time | ❌ |
| Arbitrary metadata key |
✅ {meta, Key} |
❌ |
Custom tags and metadata indexes are what make DCB filters fast: the server-side condition check hits the index, not a full scan of the global log.
BEAM-native consensus
KurrentDB uses its own leader election algorithm (not published as a standalone specification). ReckonDB’s store is built on Ra, the Raft implementation that ships in RabbitMQ, and Khepri, used in production in RabbitMQ 4.0.
The practical difference: Ra is a scrutinised, formally-specified Raft implementation with OTP supervision trees. A failed Ra member is isolated by OTP. The BEAM actor model gives you process-level fault isolation that the JVM-based cluster coordination in KurrentDB does not have.
Tamper resistance
ReckonDB stores an HMAC + hash chain per event, verifiable at read time. KurrentDB has no equivalent. For audit log, financial records, or regulatory compliance use cases, this is a hard requirement that KurrentDB cannot satisfy without a layer above the store.
Licence
KurrentDB is under the Business Source Licence (BSL). BSL permits use below a threshold (currently production use for organisations under a certain revenue), with the restriction that it converts to Apache-2.0 after a specified period. The practical risk: if your usage exceeds the BSL threshold, you’re commercial. KurrentDB/Kurrent Cloud is the commercial offering.
ReckonDB is Apache-2.0 with no usage restrictions.
Where KurrentDB Leads
Battle-tested at scale
EventStoreDB has been in production since 2011, with documented deployments at thousands of companies. ReckonDB is young. If your requirement is “used by 10,000 teams with public post-mortems,” KurrentDB wins.
Client ecosystem
KurrentDB has official, maintained SDKs for .NET, Java, Go, Python, Node.js, and Rust. ReckonDB has Go (reckon-go) and Erlang/Elixir (evoq + reckon-evoq). If your team is Python, .NET, or Node.js, KurrentDB is ready today.
HTTP/JSON API
KurrentDB exposes a full HTTP/JSON API alongside gRPC. ReckonDB, through reckon-gateway, also offers both: gRPC plus an HTTP/JSON REST API over the core surface (and a browser admin UI). Teams that want to avoid protobuf toolchain setup can curl either store from day one.
Managed cloud
Kurrent Cloud is a fully managed KurrentDB hosting. ReckonDB requires self-hosting or your own infrastructure.
Competing consumers
KurrentDB’s persistent subscriptions with competing consumers are mature and configurable. ReckonDB’s competing consumer implementation is in development.
Web admin UI
KurrentDB ships an embedded admin UI. ReckonDB’s UI is the reckon CLI + reckon-lazy
(TUI). A web UI for browsing event streams, checking stream health, and managing
subscriptions does not exist yet in ReckonDB.
Who Should Choose Which
Choose ReckonDB if:
- You need filter-based DCB, cross-aggregate consistency without enumerating streams
- You’re building on BEAM (Erlang/Elixir) and want a native embedded store
- You need arbitrary secondary indexes (custom tags, metadata queries)
- Tamper resistance is a compliance requirement
- You want Apache-2.0 with no usage restrictions
- You’re embedding a store in a single-node mode (laptop → cluster, same API)
Choose KurrentDB if:
- You need a .NET, Python, Java, or Node.js SDK today
- Competing consumers (work queue delivery) are a current requirement
- You want a managed cloud offering
- Your organisation has used EventStoreDB for years and migration cost is high
- You need HTTP/JSON without a protobuf toolchain
The DCB Distinction in One Paragraph
KurrentDB’s multi-stream append is stream-enumeration-based atomic write: useful, correct, a real improvement. ReckonDB’s DCB is filter-based conditional append: you give the store a tag/type filter and a position cutoff, and the store atomically checks whether any event matching that filter appeared after your cutoff position, refusing the write if one did. You never enumerate streams. The filter is evaluated inside a single Raft log entry. The two primitives solve overlapping but distinct problems; the filter-based form is strictly more expressive for open-ended consistency invariants.