Embedded database for .NET · ACID · concurrent
A real database, inside your app.
An embedded, object-oriented database for .NET. Your data stays in files you can open, diff and commit.
ACID transactions, thousands of concurrent readers and three storage formats, in a library you add with one package. A hundred thousand rows load in about a second; a lookup takes four microseconds.
// a database is a directory
using var db = new XodContext("app.xod");
db.Insert(new Customer {
Name = "Nadia",
Orders = { new Order { Status = "open" } }
});
// indexed query, not a table scan
var open = db.Query<Order>(o => o.Status == "open")
.ToList(); Why XOD
An embedded database that behaves like a database.
Your objects, not a mapping layer
Insert a POCO, query it with a lambda, get the same type back. No SQL strings, no migration files, no generated code — the object model is the schema.
Many readers, one writer
Per-table locks, queued transactions and a commit journal. Eight threads read at over 140,000 rows a second while a writer keeps committing.
Fast, and it stays fast
A hundred thousand rows load in about a second, a lookup takes four microseconds, and paging to the end of a large table is instant — measured, not estimated.
Compact by default
A gigabyte of rows fits in about a gigabyte of files, with no compression tricks and no compaction step. What you insert is roughly what you store.
A database per service
It lives in the service process and in its own directory. No server to run, no connection pool to tune, no port to open.
Runs where servers cannot
Raspberry Pi, industrial PCs and .NET boards. Crash-safe writes when power is cut, and the same engine as the one in your data centre.
Three storage engines
Same code. Different files.
The format is a setting on the context, and XodMigrator converts an existing
database without your model assembly. Pick readable, or pick small.
readable pages · default
XML
Plain XML files, one per table page. Open them in an editor, diff them in a pull request, grep them at 2 a.m.
- Fastest for row reads
- Human-readable and diffable
- The default format
readable pages · tool-friendly
JSON
The same page model in JSON, for pipelines that already speak it. Larger on disk than XML and slower on a cold read, but every file opens in any JSON tool.
- Readable by any JSON tool
- Larger on disk than XML
- Good for interchange and inspection
Brotli-compressed · smallest
Binary
Compressed pages: the smallest files XOD can write. Reading a row means decompressing its page, so use it for archives, devices and read-light workloads.
- Smallest footprint
- Best for archives and devices
- Slowest per-row access
Proof
Measured on one machine, published in full.
Four numbers from the current benchmark run: 100,000 rows at 250 MB and 400,000 at 1 GB, on the hardware in the studio. Every run is stamped with the commit that produced it, so the numbers can be checked rather than trusted.
One transaction, 250 MB of records, index included.
XOD XML
About four microseconds per read on a warm database.
XOD XML
Deep paging without reading the rows before it.
XOD XML
Eight threads reading while another writes.
XOD XML
Get started
Install it like any other package.
One package, one directory, one line of code. There is no server to run, no port to open and no schema migration to apply — the database is created on first use and the files stay yours.
# add the package to your project
dotnet add package Xod
# run it: the database is a directory
dotnet run using var db = new XodContext("app.xod");
db.Insert(new Customer {
Name = "Nadia",
Orders = { new Order { Status = "open" } }
});
// indexed query, not a table scan
var open = db.Query<Order>(o => o.Status == "open")
.ToList(); - Runs on .NET 8 and .NET 9
- No server, no port, no connection string
- Data files are yours: inspect, diff, back up with a file copy
Package: nuget.org/packages/Xod · Source: github.com/mhsallam/xod