Skip to content

The search box knows all the secrets -- try it!

Fisher is part of the Critter Stack ecosystem.

JasperFx Logo JasperFx provides formal support for Fisher and other Critter Stack libraries. Please check our Support Plans for more details.

Introduction

Welcome to the Fisher documentation!

What is Fisher?

Fisher is a .NET library for building applications using a document-oriented database approach and Event Sourcing, backed by SQLite.

Fisher is part of the Critter Stack ecosystem and mirrors the API patterns of Marten (PostgreSQL) and Polecat (SQL Server), so a team already using either one will recognise nearly everything here.

TIP

If you've used Marten or Polecat before, you'll feel at home. Same interface names, same session patterns, same projection model. What differs is what SQLite makes cheap and what it makes impossible — and this documentation says which is which rather than leaving you to find out.

The thing that makes Fisher different from its siblings is not the SQL dialect. It is that there is no database server. SQLite runs inside your process, a store is a file, and the "network round trip" that shapes so much of a document database's design simply is not there.

Fisher is built on:

  • JasperFx.Events — the shared event, projection and daemon abstractions the whole Critter Stack implements,
  • Weasel.Sqlite — schema management, migrations and data access,
  • Weasel.Storage — the dialect-neutral document and event storage runtime extracted from Marten.

Fisher supplies the SQLite dialects and the storage seams. Everything above them is shared with Marten and Polecat, which is why a projection written for one store runs unaltered on another.

Main Features

FeatureDescription
Document StorageStore entities as JSON documents with full LINQ querying support.
Event StoreFull event store with stream management, projections and subscriptions.
Strong ConsistencyDocuments and events commit in one SQLite transaction.
LINQ QueryingWhere, ordering, paging, projections, grouping, aggregates and joins.
Event ProjectionsInline, live and asynchronous read models.
Automatic Schema ManagementWeasel.Sqlite creates and migrates tables.
Optimistic ConcurrencyGuid version or numeric revision.
Multi-TenancyConjoined tables, or a database file per tenant.
Async DaemonBackground projection processing.
ASP.NET Core IntegrationStreaming JSON results and ETag handling.
EF Core IntegrationA DbContext writing inside Fisher's transaction.

Critter Stack Ecosystem

LibraryPurpose
MartenPostgreSQL document database and event store
PolecatSQL Server document database and event store
WolverineMessaging and command processing
JasperFxCore framework and event sourcing abstractions
WeaselDatabase schema management

Fisher vs Marten and Polecat

The API is deliberately the same. The storage decisions are not, and these are the ones worth knowing up front:

ConcernMarten (PostgreSQL)Polecat (SQL Server)Fisher (SQLite)
Schemasreal schemasreal schemasnone — folded into the table prefix
JSONjsonbnative jsonTEXT + json1 functions
TimestampstimestamptzdatetimeoffsetISO-8601 TEXT, fixed width, UTC
BooleansbooleanbitINTEGER 0/1
Guidsnative uuiduniqueidentifierlowercase canonical TEXT
Event sequencesequenceIDENTITYINTEGER PRIMARY KEY AUTOINCREMENT
Document upsertINSERT … ON CONFLICTMERGEINSERT … ON CONFLICT … RETURNING
Append concurrencyadvisory lockUPDLOCK, HOLDLOCKBEGIN IMMEDIATE
Writersmanymanyone per database file
SerializationSTJ or NewtonsoftSystem.Text.JsonSystem.Text.Json

The single-writer row is the one that propagates. It is why Fisher's unit of work is strictly sequential, why transaction participants and raw SQL commands matter more here than on either sibling, why a busy retry is a real policy rather than a formality, and why database-per-tenant is a performance feature and not only an isolation one.

What Fisher deliberately does not do

  • There is no message bus. Projections can publish side effects, and the default outbox drops every message. Delivery is a bus integration's job here as it is on Marten and Polecat.
  • There is no table partitioning. SQLite has no partition functions or schemes, and the nearest equivalent carries none of the operational properties that make the feature worth having.
  • There is no hot-cold daemon failover. Leader election across nodes means several processes sharing one file, which SQLite does not make safe. The daemon runs Solo.
  • Fisher ships no binary event serializer. The seam exists; choosing MessagePack or protobuf is your application's decision about how its data ages.

History and Origins

The Critter Stack names its projects after animals, and the mustelid family has been good to it. A fisher is a small, quick North American mustelid — a cousin of the marten and the polecat, and the smallest of the three, which is about right for the store that fits in a file.

Released under the MIT License.