# Marten: a .NET document DB and event store on PostgreSQL

> Marten turns PostgreSQL into a document database and an ACID event store for .NET developers, with LINQ queries and user-defined projections. The trade-off is that you are running your application data on the database you already operate.

**JasperFx/marten** — .NET Transactional Document DB and Event Store on PostgreSQL

- Repository: https://github.com/JasperFx/marten
- Website: https://martendb.io
- Stars: 3,458 · Forks: 560
- Language: C#
- License: MIT
- Published: 2026-09-23 · Updated: 2026-09-23 · Language: en
- Canonical page: https://hysenlabs.com/projects/jasperfx-marten

## What Marten solves for a .NET team already running PostgreSQL

Marten is a .NET library that lets you use PostgreSQL as a document database, and also as an event store with user-defined projections. The README states the team's position plainly: "a document database has far reaching benefits for developer productivity over relational databases with or without an ORM tool." That is a design opinion, not a neutral description, and it explains most of the API surface.

The audience is .NET developers who would otherwise be mapping objects through an ORM onto relational tables, or standing up a separate document database next to PostgreSQL. Marten removes the second database from the picture. Your documents live in PostgreSQL, your transactions are PostgreSQL transactions, and your operational tooling (backups, replication, monitoring) is the tooling you already have. For a team that has run PostgreSQL for years, that is a smaller change than introducing a new storage engine with its own failure modes.

The event store side is the more consequential half. Marten provides an ACID-compliant event store with user-defined projections against event streams. An event store is not a document database with a different name; the write model is append-only streams, and the read model is something you project out of them. Marten puts both in the same PostgreSQL instance, which is the reason the transactional guarantee is possible at all.

## How documents, streams and projections fit together

The mechanism the README makes visible is that PostgreSQL's JSON support carries the document store, and the same database carries the event store. Documents are serialized JSON, and queries are expressed in .NET and translated to SQL against that JSON. The repository's top-level entries include a docs/ directory and a documentation/ directory, and the homepage points at martendb.io for the full reference, so the query translation rules live there rather than in the README.

On the event side, the flow is: append events to a stream, and let projections derive read models from those events. The README says the event store is ACID-compliant and that projections are user-defined. The practical consequence is that an append and its projection update can be committed together, so a read model does not drift from the stream when a process dies mid-write. That is the property most people adopt Marten for.

One architectural detail is worth flagging because it constrains deployment. The README states that the async daemon requires PostgreSQL 13 or later because it calls pg_current_snapshot(), and that CI runs postgres:15-alpine and postgres:latest. The async daemon is the background process that keeps projections current, so this is not an optional component. If you are on PostgreSQL 12 or older, the asynchronous projection path is closed to you.

Patching is the other mechanism that changed shape. Marten supports native patching since v7.x, documented under the patching API. Earlier versions used PLV8, a JavaScript procedural language for PostgreSQL. The README is explicit that PLV8 is no longer part of developing Marten: the patching API it once backed was replaced by the native implementation, and the compose image dropped the extension. Applications still using it need the separate Marten.PLv8 package. That is a migration cost, not a footnote.

## Installing Marten and running a first document session

Marten ships as a NuGet package. The README links the package page at nuget.org/packages/Marten, and the badge in the README tracks the current version. Add it to a .NET project with the dotnet CLI:

```bash
dotnet add package Marten
```

You need .NET SDK 8.0 or above, per the README's working-with-the-code section. You also need a PostgreSQL database. The README describes the fastest way to get one for development as running PostgreSQL in a Docker container, and the repository ships a docker-compose.yml for exactly that. From the repository root:

```bash
docker-compose up
```

That compose file builds a custom image from docker/postgres/Dockerfile, which layers PostGIS 3 and pgvector onto the official postgres:17 image. It exposes port 5432 and creates a database named marten_testing with user postgres and password postgres. Note the shm_size: '512mb' setting in the file: the comment explains that Postgres 17 keeps roughly 46MB of dynamic shared memory standing at boot, so Docker's default 64MB /dev/shm leaves parallel queries almost no headroom and the test suite can fail with "53100: could not resize shared memory segment". If you copy this compose file into your own environment, keep that setting.

For the test suite, the README says the login must be a member of the postgres role, and an environment variable named marten_testing_database holds the connection string for the testbed database. If the tests explorer cannot detect the database version automatically, the README says you can enforce it:

```shell
postgresql_version=15.3
```

The README does not give a first application code sample, so the place to start writing your first DocumentSession and defining document types is the documentation at martendb.io. The repository itself is built with the dotnet CLI: `dotnet build src/Marten.slnx` runs restore, build and test, and the build scripts (build.cmd, build.ps1, build.sh) wrap the same commands.

## Where the PostgreSQL coupling becomes a real cost

The strongest argument for Marten is also its hardest constraint: it is PostgreSQL, and only PostgreSQL. There is no adapter to another engine, and the async daemon depends on a PostgreSQL function that arrived in version 13. If your organisation standardises on SQL Server, or your managed database service caps you below PostgreSQL 13, Marten is not the tool. That is not a gap the project is working around; it is the premise.

The second cost is operational. Running the event store and the document store inside the same PostgreSQL instance that also serves your other application data means a noisy neighbour problem is possible. A projection rebuild that scans a large event table competes with the transactional workload of everything else in that database. Marten gives you transactional guarantees by putting the data together; the same decision removes the isolation a separate store would have provided.

Third, the README does not document rollback. There is no described procedure for reverting a projection or undoing a schema migration in the README. The docs at martendb.io are the place that would carry it, and anyone planning a production event store should confirm the story there before committing. Event-sourced systems are usually recoverable because events are immutable, but the read model rebuild path and its cost are not something the README addresses.

Finally, event sourcing is a modelling commitment. Marten supports it well, but a team that adopts an event store because the library makes it easy, without a domain that benefits from an append-only log, will spend more time on projection design than they saved on ORM mapping. The document database half of Marten has no such requirement, and it is the lower-risk way to start.

## Marten against a standalone document database

The obvious alternative is a dedicated document database such as MongoDB, and the difference is not the document model. Both store JSON-ish documents and both offer a .NET driver. The difference is where the transaction boundary sits and what you operate.

With a standalone document database you get a storage engine designed only for documents, with its own query planner, its own replication model, and its own operational surface. You also get a second system to back up, monitor, upgrade and secure, and you get a distributed transaction problem the moment a write needs to touch both that store and your relational data. Marten's answer is to not have that problem: there is one database, one transaction, one backup.

For event sourcing specifically, the comparison is usually against building streams on top of a relational schema yourself, or against a purpose-built event store. Marten's position is that you get ACID event streams and projections without leaving PostgreSQL, at the cost of living with PostgreSQL's performance characteristics on an append-heavy table. A purpose-built event store may handle that write pattern better; it also adds a system your team must learn. Which side of that trade you want depends on whether your bottleneck is write throughput or operational count, and the README does not make a performance claim either way.

## Licence, support and what an upgrade actually involves

Marten is MIT licensed, so the source can be used, modified and redistributed under those terms. The repository carries a LICENSE file at the top level and a postgresql.license file alongside it. This is not legal advice; if the licence terms matter to your organisation, read the LICENSE file rather than a summary.

Support is worth understanding before adoption. The README states that while Marten is open source, JasperFx Software offers paid support and consulting contracts, and links to their support plans. There is also a Discord channel and GitHub Discussions, which the README describes as the best way to reach the team quickly. For a library that sits under your persistence layer, the existence of a commercial support path is a real consideration, particularly if you are using the event store in production.

Upgrade cost is the part that needs the most attention. The release cadence visible in the repository is frequent: V9.39.0, V9.38.0 and V9.37.0 all appear within about a week, with the most recent push on 2026-09-22. Frequent releases are not automatically a problem, but they do mean you should pin a version and read release notes rather than floating. The PLv8 removal is the concrete example of why: an application written against the older patching API does not simply keep working, it needs the separate Marten.PLv8 package. The README points at the native patching API as the replacement, and anyone upgrading across that boundary should budget for it. The repository also carries planning documents at the top level, including DCB_IMPLEMENTATION_PLAN.md and PLAN-xunit3-migration.md, which suggest ongoing internal change; treat those as evidence that the codebase moves, not as a stability guarantee.

## Conclusion

Adopt Marten when your team already runs PostgreSQL and your domain fits document storage or event sourcing, and you want the write and its projections in one database transaction. Skip it if you need a database that is not PostgreSQL, if you want a server you install and manage separately from your application code, or if your team has no .NET. Before committing, check the version of PostgreSQL you are on (the async daemon requires 13 or later because it calls pg_current_snapshot()), confirm that your projections can be rebuilt from the event stream, and read the patching API documentation if you are upgrading an application that still depends on the Marten.PLv8 package.

## FAQ

### What is Marten in the .NET ecosystem?

Marten is a .NET library that lets you use PostgreSQL as a document database and as an ACID-compliant event store with user-defined projections. It is distributed as the Marten NuGet package and documented at martendb.io.

### Which PostgreSQL version does Marten require?

The README states that the async daemon requires PostgreSQL 13 or later because it calls pg_current_snapshot(). CI runs postgres:15-alpine and postgres:latest, and the docker-compose.yml in the repository builds on the official postgres:17 image.

### Does Marten still need the PLV8 extension?

No. The README says PLV8 is no longer part of developing Marten because the patching API it backed was replaced by the native implementation, and the compose image dropped the extension. Applications that still use it need the separate Marten.PLv8 package.

### What .NET version do I need to build or contribute to Marten?

The README's working-with-the-code section lists .NET SDK 8.0 or above as a prerequisite, alongside PostgreSQL 13 or above. The solution is built with dotnet build src/Marten.slnx, or through the build.cmd, build.ps1 and build.sh scripts.

### Is Marten free to use in a commercial product?

Marten is MIT licensed, and the repository carries a LICENSE file at the top level. The README also notes that JasperFx Software offers paid support and consulting contracts separately from the open source licence.

## Sources

- [JasperFx/marten on GitHub](https://github.com/JasperFx/marten)
- [License: MIT](https://github.com/JasperFx/marten/blob/master/LICENSE)
- [Project website](https://martendb.io)
- [README](https://github.com/JasperFx/marten/blob/master/README.md)
- [Releases](https://github.com/JasperFx/marten/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/jasperfx-marten
