Your documents.
Your stack.
A consistent .NET API for documents, indexed queries, and atomic writes. Run in memory, on disk, in the browser with localStorage, sessionStorage, or IndexedDB, or with Redis, PostgreSQL, MongoDB, and Cosmos DB.
{
"id": "customer-1",
"name": "Alex",
"active": true
}Choose your storage
Storage that fits
your application.
Use the storage your workload needs.
Keep a consistent API as your application grows.
Memory
Fast, in-process storage for temporary data, tests, and getting started.
FileSystem
In-memory documents backed by a JSON file. Local persistence for a single process.
Redis
Share documents and indexes across instances. No Redis modules or Lua required.
PostgreSQL
Persistent documents, SQL-backed queries, and atomic transactions.
MongoDB
Native documents with server queries and atomic transactions.
Cosmos DB
Azure NoSQL documents with server queries and partition-scoped atomic batches.
CouchDB
JSON documents over HTTP with revision checks and Mango indexes.
localStorage
Small browser snapshots that persist across sessions, with in-memory queries.
sessionStorage
Small browser snapshots scoped to the current tab session, surviving reloads.
IndexedDB
Browser snapshots committed through IndexedDB transactions, with in-memory queries.
From setup to
your first document.
Get a container, add a document, read it back. Async operations and dependency injection fit naturally into your .NET application.
Your first document, step by stepInstall a provider.
Shared dependencies come with it.
dotnet add package Soenneker.Librarian.Memory
// Register your storage provider.
builder.Services.AddMemoryLibrarianDatabaseAsSingleton();
// Inject ILibrarianDatabase into your service.
var users = await database.GetContainer("users");
await users.AddItem("user-1", """{"name":"Alex"}""");
var json = await users.GetItem("user-1");
The pieces your
data layer needs.
Work with your types.
Typed repositories handle serialization and document operations. Register source-generated JSON contracts for trim-safe, Native AOT compatible models.
Native AOT guide ↗Find more. Scan less.
Filter, order, count, and page with LINQ or explicit async index methods. Supported LINQ queries create indexes automatically and maintain them on writes.
Query capabilities ↗Keep changes together.
Apply related writes across containers in one atomic batch. Add conditions to detect conflicting changes before any writes are applied.
Atomic batch guide ↗See how Librarian
compares.
Librarian, LiteDB, and sqlite-net running the same queries against 100,000 documents. All use in-memory storage with warm indexes.
Methodology & benchmark source ↗| Query | Librarian | LiteDB 5.0.21 | sqlite-net 1.11.285 |
|---|---|---|---|
| Equality · 10 documents | 8.983 | 29.341 | 11.866 |
| Range page · 10 documents | 10.337 | 41.159 | 13.113 |
| Count · 10 matches | 2.013 | 29.925 | 3.574 |
| Exists · 50% hits | 2.228 | 22.159 | 2.537 |
| First match | 2.989 | 18.134 | 6.204 |
| Skip 90,000 · take 10 | 8.644 | 53,694.283 | 1,240.940 |
Compare managed allocations Bytes per operation
| Query | Librarian | LiteDB | sqlite-net |
|---|---|---|---|
| Equality · 10 documents | 6,840 | 63,440 | 9,064 |
| Range page · 10 documents | 8,665 | 89,563 | 11,801 |
| Count · 10 matches | 1,600 | 65,006 | 2,176 |
| Exists · 50% hits | 1,600 | 44,621 | 344 |
| First match | 1,896 | 43,887 | 4,864 |
| Skip 90,000 · take 10 | 6,944 | 189,235,872 | 8,912 |
Managed allocations on the executing thread only. SQLite native allocations are excluded. sqlite-net allocates fewer managed bytes for the existence check.