Event sourcing in .NET: comparing KurrentDB, Marten, and Cratis Chronicle
Choosing an event sourcing foundation for a .NET system is a long-lived decision. The event store outlives frameworks, UI rewrites, and often the team that chose it. Yet most comparisons available today reduce to popularity: the tools with the most blog posts win the evaluation before it starts.
This comparison takes a different approach. Every factual row names the exact versions compared and is reproducible from public documentation and released packages. Where our own product appears, the same rules apply — including the limitations.
The candidates
Section titled “The candidates”- KurrentDB (formerly EventStoreDB) — a purpose-built event store database with clients for multiple languages. You bring your own CQRS layer and read-model infrastructure.
- Marten — a .NET library that turns PostgreSQL into a document and event store. Deep .NET integration; PostgreSQL is a prerequisite; .NET is the boundary.
- Cratis Chronicle — an event-sourcing database and processing runtime with a first-class .NET SDK and released TypeScript, Java/Kotlin (JVM), and Elixir client packages. Pairs with Arc (an opinionated CQRS application framework for ASP.NET Core with TypeScript proxy generation) and a React component library.
How this comparison is made
Section titled “How this comparison is made”Compared versions
Section titled “Compared versions”All facts retrieved 2026-08-28 unless a row states otherwise.
| Tool | Compared version | Version source |
|---|---|---|
| KurrentDB (formerly EventStoreDB) | Server 26.0 documentation series; 26.0.3 is the release named in the official installation documentation | docs.kurrent.io/server/v26.0/quick-start/installation.html (retrieved 2026-08-28) |
| Marten | 9.30.0 (latest stable package on NuGet at retrieval) | nuget.org listing for Marten (retrieved 2026-08-28) |
| Cratis Chronicle | 17.0.0 (latest stable Cratis.Chronicle package on NuGet at retrieval); server distributed as the cratis/chronicle Docker image | nuget.org listing for Cratis.Chronicle; hub.docker.com/r/cratis/chronicle (retrieved 2026-08-28) |
The comparison matrix
Section titled “The comparison matrix”| Row | KurrentDB (server 26.0) | Marten (9.30.0) | Cratis Chronicle (17.0.0) |
|---|---|---|---|
| License | Kurrent License v1 (KLv1). The KurrentDB documentation states the source code is available to view and that KLv1 “is not an OSI-approved Open Source License”; enterprise features are enabled with a license key. | MIT License. | MIT License. |
| Storage model | Purpose-built, event-native database; events are stored in streams inside KurrentDB’s own storage engine. | Library that uses PostgreSQL as the underlying data store, using its JSON support and ACID compliance; PostgreSQL is a prerequisite. | Event-sourcing database with pluggable storage-provider implementations documented in the repository README: MongoDB (default), PostgreSQL, SQL Server, and SQLite, plus an in-memory provider. |
| Language clients | Official gRPC client SDKs listed for Python, Node.js (JavaScript/TypeScript), Java, .NET, Go, and Rust; community clients listed for Ruby, Elixir, and PHP; an HTTP interface also exists (AtomPub-based application API disabled by default and planned for removal). | .NET library; runs inside a .NET application process. | First-class .NET client SDK (Cratis.Chronicle on NuGet). Released client packages also on public registries: @cratis/chronicle 3.1.0 on npm (MIT), io.cratis:chronicle 2.10.0 on Maven Central, cratis_chronicle 2.2.0 on Hex (MIT). A Python client is coming soon: no package is published on PyPI as of the retrieval date, and no commitment is implied. |
| Subscriptions / event processing | Catch-up subscriptions (client keeps position) and persistent subscriptions (server keeps position, competing-consumers pattern, at-least-once delivery across consumer groups). | Subscription model (ISubscription, documented since 7.7) running in Marten’s async daemon subsystem as a background process inside the application, for pushing captured events into custom processing. | Reactors (react to events as they occur), Reducers (imperatively transform events into typed read models), and Observers (low-level event subscriptions with guaranteed delivery), as documented in the repository README. |
| Projections / read models | Server-side projections subsystem: built-in (system) projections and user-defined JavaScript projections; projections require the event body to be JSON. The docs note many read-model problems are better served by a separate read model populated by a catch-up subscription. | Rich projection support for read-side views: inline projections (in the capture transaction), async projections (background, eventually consistent), and live projections (evaluated on demand). | Declarative, fluent projection builders with join, set, and remove support, producing typed read models, as documented in the repository README. |
| Hosting model | Separate database server process: single node or a highly-available cluster (three nodes for cluster deployment); installable from Linux package repositories, on Windows, or via Docker images; some features require a license key. | In-process library: embedded in the host .NET application; background projection/subscription work runs in the async daemon inside the application. Requires a PostgreSQL database. | Separate server (Chronicle Kernel) run via the cratis/chronicle Docker image, exposing gRPC, REST API, and the Web Workbench management dashboard on a single port; the latest-development image bundles MongoDB for local development. |
Row sources
Section titled “Row sources”All retrieved 2026-08-28:
- KurrentDB — license, client list, protocols: docs.kurrent.io/server/v26.0/quick-start/ (Introduction); hosting, packages, Docker, license keys, 26.0.3: docs.kurrent.io/server/v26.0/quick-start/installation.html; projections: docs.kurrent.io/server/v26.0/features/projections/; persistent subscriptions: docs.kurrent.io/server/v26.0/features/persistent-subscriptions.html.
- Marten — positioning, PostgreSQL store: martendb.io (home) and martendb.io/events/; projection types: martendb.io/events/ (terminology: inline/async/live projections); subscriptions: martendb.io/events/subscriptions; license: github.com/JasperFx/marten
LICENSE(MIT); version: nuget.org listing forMarten(9.30.0). - Cratis Chronicle — identity, kernel/SDK/Workbench/storage providers (MongoDB default; PostgreSQL, SQL Server, SQLite, in-memory), reactors/reducers/projections/observers, Docker hosting: github.com/Cratis/Chronicle
README.md; license: github.com/Cratis/ChronicleLICENSE(MIT); versions and client packages: nuget.org (Cratis.Chronicle17.0.0), npm (@cratis/chronicle3.1.0), Maven Central (io.cratis:chronicle2.10.0), hex.pm (cratis_chronicle2.2.0), pypi.org (nocratis-chroniclepackage published), hub.docker.com/r/cratis/chronicle.
Ecosystem and supporting products
Section titled “Ecosystem and supporting products”An event store rarely ships alone. Each of the compared tools names its own supporting products; the same method applies here — every cell restates the named vendor’s own public listing or documentation, with retrieval dates, and implies nothing about quality, integration depth, or superiority.
| Row | KurrentDB (server 26.0) | Marten (9.30.0) | Cratis Chronicle (17.0.0) |
|---|---|---|---|
| Wider product family | Official gRPC client SDKs for six languages plus community clients (see the Language clients row); the documented server feature set includes projections, persistent subscriptions, and a Connectors subsystem (next row). | Listed by JasperFx as part of the “Critter Stack”, described as “one family of .NET tools for event sourcing, document storage, and messaging”: Wolverine (messaging), Polecat (SQL Server), Fisher (SQLite), Weasel (schema), Alba (integration testing), and CritterWatch (monitoring). | Part of the Cratis ecosystem: Arc (an opinionated CQRS application framework for ASP.NET Core with commands, queries, validation, authorization, and TypeScript proxy generation), Components (a React component library aligned with Arc application patterns), the Cratis CLI (terminal workflows for inspecting and diagnosing Chronicle), and the Web Workbench management dashboard exposed by the server. Released language clients for .NET, TypeScript, JVM, and Elixir (see the Language clients row). |
| Pushing events to other systems | Server-side Connectors subsystem, documented as pre-installed and enabled by default: each connector runs a catch-up subscription that can filter or transform events and push them to an external system via a sink; the documented sink catalog lists Elasticsearch, HTTP, Kafka, MongoDB, RabbitMQ, and Serilog sinks. | Subscriptions running in the async daemon push captured events into custom processing (see the Subscriptions row); messaging integration is positioned in the wider Critter Stack through Wolverine. | The server exposes gRPC and REST APIs (see the Hosting model row); Reactors provide documented event-driven processing, and Arc’s TypeScript proxy generation carries contracts to the frontend. |
| AI assistance | No entry compiled for this row; per the caveats, absence means only that it was not found in the sources cited for this page. | The JasperFx site describes its libraries as “optimized for low-friction development, testability, and AI-assisted workflows” and references its AI skills in current posts. | Cratis documents free AI skills, rules, and diagnostics for AI-assisted development on the AI page; current availability and distribution status are stated on that page. |
Ecosystem row sources
Section titled “Ecosystem row sources”All retrieved 2026-08-28:
- KurrentDB — Connectors overview (pre-installed, enabled by default, catch-up subscription, filter/transform, sinks): docs.kurrent.io/server/v26.0/features/connectors/; sink catalog: docs.kurrent.io/server/v26.0/features/connectors/sinks/.
- Marten / Critter Stack — family listing and wording (“one family of .NET tools for event sourcing, document storage, and messaging”; Wolverine, Polecat, Fisher, Weasel, Alba, CritterWatch; “AI-assisted workflows”): jasperfx.net; Wolverine documentation: wolverinefx.net.
- Cratis Chronicle — Arc: cratis.io/arc/; Components: cratis.io/components/; CLI: cratis.io/cli/; Workbench: github.com/Cratis/Chronicle
README.md; AI skills, rules, and diagnostics: cratis.io/ai/; client packages: registry listings cited under Row sources above.
Caveats and limitations
Section titled “Caveats and limitations”- This matrix compares documentation, not behavior. Every cell restates what the named tool’s own public documentation or registry listing says at the named version and retrieval date. It does not test, measure, or rank anything, and absence of a capability from a cell means only that it was not found in the cited source — not that the tool lacks it.
- Client existence is not client parity. A listed client package says nothing about feature coverage relative to the primary client — for any tool in this table, including Chronicle.
- An ecosystem listing is not an integration or quality claim. The ecosystem rows restate each vendor’s own product-family listing at the retrieval date. They say nothing about how well the pieces work together, how complete any supporting product is, or how the families compare — and an empty or missing entry means only that nothing was found in the cited sources.
- Chronicle’s storage-provider row restates the repository README’s own listing. The repository README documents pluggable storage with MongoDB (default), PostgreSQL, SQL Server, SQLite, and in-memory providers; the row sticks to that cited wording and implies nothing about provider parity or completeness.
- The Python client is strictly coming soon. Pre-alpha, unpublished, and no commitment implied.
- KurrentDB licensing nuance. The license row quotes KurrentDB’s own documentation; read KLv1 yourself for terms. This page draws no conclusion about fitness of any license for any use.
- Versions move. Each compared tool releases on its own cadence; every cell is pinned to the versions and retrieval dates above and may be stale the day after retrieval.
How to choose
Section titled “How to choose”Rather than a winner, use fit questions:
- Do you want a dedicated event database and your own application layer? A purpose-built store with bring-your-own CQRS gives maximum control and maximum assembly work.
- Are you a PostgreSQL shop wanting minimum new infrastructure? A library-on-PostgreSQL approach is hard to beat for operational simplicity.
- Do you want event sourcing, CQRS, and frontend integration designed together? An integrated platform trades some flexibility for coherence: projections, read models, generated frontend contracts, and query updates that share one design.
- Is your organization polyglot? Check which client languages are first-party and what each client actually supports — client existence is not client parity, for any tool including ours.
- Who explains the system at 3 a.m.? Compare the operational surfaces: what does each tool show you about observer progress, failed projections, and replay?
What we deliberately did not claim
Section titled “What we deliberately did not claim”This comparison states released, verifiable facts. It does not claim any tool is faster, more scalable, more reliable, or more production-proven than another — those claims require benchmarks and evidence this page does not carry. Where a capability is listed for Chronicle, it comes from the named released version; the same courtesy is extended to every tool compared, from that tool’s own documentation.
How this page stays current
Section titled “How this page stays current”This matrix is re-verified — every cell checked against the then-current released versions with new retrieval dates — whenever a compared tool ships a new major or minor server/package release, a compared tool changes its license or client list, or 90 days elapse since the last recorded retrieval date. If a compared tool disputes a row and it cannot be re-verified, the row is corrected or removed.
If you spot a cell that no longer matches its source, tell us — we will re-verify and fix it.