Introducing Fisher: Sqlite Backed Document Db & Event Store Critter

I know, you were probably wandering around today and thinking to yourself, my life would be more complete if there was just a library out there that gave you the developer experience of the tried and true Marten library, but backed by Sqlite so you could just get things done on projects that don’t really need a database server.

To that end, let me introduce Fisher, our latest Critter Stack library that is officially our SQLite-backed Event Store and Document Database inside the Critter Stack. I pushed the first Nuget version today as 0.5.0 if you want to pull it down and play with an early version.

Fisher is a document database and event store for .NET, in the same family as Marten and Polecat — except that it runs on SQLite, which means it runs inside your process, and there is no database server anywhere in the picture.

dotnet add package Fisher
builder.Services.AddFisher(opts =>
{
opts.Connection("Data Source=app.db");
});

That’s the whole setup. No container, no connection to a host, no credentials, no waiting for a health check before your integration tests can run. Just go.

Why bother?

The Critter Stack already has two of these. Marten has been running on PostgreSQL for over a decade, and Polecat brought the same model to SQL Server 2025 earlier this year. So why a third?

Because I thought this would be a valuable persistence option for our commercial CritterWatch tool to help adoption, and also as a persistence option for an “AI-related commercial development tool to be named later” from JasperFx.

Because a meaningful number of .NET applications don’t want a database server, and up to now the answer from us was “well, use one anyway.” Think about:

  • Desktop and CLI applications
  • Edge and on-premises deployments where somebody else operates the box
  • Single-node services that will never scale out and shouldn’t pretend they might
  • Embedded reporting

It’s the same API

This is not a new library with a familiar accent. It implements the same JasperFx.Events abstractions the other two do, so a projection you wrote for Marten runs on Fisher unaltered:

// Documents
session.Store(new User { FirstName = "Jane", LastName = "Doe" });
await session.SaveChangesAsync();
var users = await session.Query<User>()
.Where(x => x.LastName == "Doe")
.ToListAsync();
// Eventsvar stream = session.Events.StartStream<Order>(new OrderPlaced("Acme", 199.95m));
await session.SaveChangesAsync();
var order = await session.Events.AggregateStreamAsync<Order>(stream.Id);

Fisher passes all 32 suites and 272 tests of JasperFx.Events.ComplianceTests, the shared cross-store suite Marten and Polecat also enroll in. That’s not me grading my own homework — it’s the same definition of correct that the other two are held to.

What’s in the box for 0.5.0: documents over all four identity types plus strong-typed wrappers, hierarchies, soft deletes, optimistic concurrency in both flavors, patching, bulk insert, duplicated fields, indexes, foreign keys, and a LINQ provider that does joins, grouping, aggregates and both paging styles. On the event side: every projection shape across every lifecycle, the async projection daemon, subscriptions, DCB tags, natural keys, event data masking, stream compacting, and both tenancy styles. Plus Fisher.AspNetCore and Fisher.EntityFrameworkCore.

Why “Fisher?”

This is a Fisher (sometimes called a “Fisher Cat”), yet another member of the Mustilidae family and essentially a “big marten”:

Some important details along the way…

Like I said earlier, Marten has been around for over a decade now and it’s been the most successful OSS project of my career (StructureMap has more downloads, but who cares, there’s a bazillion perfectly decent IoC containers out there). We added Polecat earlier this year to finally extend our event sourcing support to SQL Server using Marten’s API and usage as a pattern. Supporting Sqlite seemed like the obvious next step to have a true embedded database option for some of JasperFx’s work — plus Babu has been advocating for that for awhile!

Along the way as you might expect, we’ve made some intermediate steps to make this new multiple database engine support possible and hopefully sustainable over the long run:

  1. As part of Marten 8.0 last year, a great deal of the abstractions, projections support, and plenty of non-PostgreSQL dependent code for event sourcing in Marten was pulled out into a now shared JasperFx.Events library
  2. I purchased a Claude Max plan for JasperFx, just to be honest here
  3. Polecat 1/2/3 was built against JasperFx.Events in essentially a “just copy Marten” AI prompt
  4. As part of Marten 9.0, we pulled as much common code between Marten and Polecat into lower level, shared Weasel libraries
  5. For Polecat 5.0, we lifted a new shared Weasel.Storage library out of Marten, then shared that dependency with Polecat to standardize a lot more of the internal mechanics of the two libraries and eliminate some Polecat specific code. My hope was and is that that effort will make it easier for us to address problems or even enhancements in a generic way
  6. Recently, we also lifted quite a few automated tests in Marten as a new “event sourcing and document database” compliance test suite that we now share between Marten, Polecat, and Fisher. That effort flushed out some inconsistencies and a few bugs in Polecat, now fixed.
  7. Fisher was mostly built to the new compliance test suites

Again, just to be honest, I don’t think that either Polecat or Fisher would have been economically feasible without the heavy utilization of the AI assisted development. And also, as always, I think the AI assisted development goes a lot better when you can supply very clear acceptance criteria like the compliance tests.