Benchmarks

Fast where it counts.

One recorded run, five engines, the same rows, the same operations and the same timer. The board at the top shows where XOD leads; the cards below show every configuration, including the ones where another engine is faster. Nothing on this page is typed by hand — it is rendered from the result files in the repository.

data set 75 runs generated 2026-11-05 20:33Z v1.2.7 at 028cd2d (clean) · .NET 9.0.4

Where XOD leads

Concurrency · 250 MB
Typical read latency, 8 threads
XOD JSON 5 µs
Concurrency · 250 MB
Slow reads, 8 threads (p99)
XOD XML 320.5 µs
Concurrency · 250 MB
Reads per second, 8 threads
XOD XML 177,161 reads/s
Concurrency · 250 MB
Writes per second, 8 threads
XOD XML 5,071 writes/s
Flat · 1 GB
Bulk load, 100k rows
XOD XML 6,409 ms
Flat · 1 GB
Jump deep into a result set
XOD JSON 0.203 ms
Flat · 1 GB
20 queries on an index
XOD JSON 39.2 ms
Flat · 1 GB
1,000 lookups by key
XOD Binary 2.743 ms
Flat · 1 GB
Size on disk
XOD Binary 282.2 MB
Flat · 250 MB
Bulk load, 100k rows
XOD XML 1,183 ms
Flat · 250 MB
Jump deep into a result set
XOD Binary 0.078 ms
Flat · 250 MB
20 queries on an index
XOD Binary 7.96 ms
Flat · 250 MB
Peak memory
XOD XML 406.7 MB
Flat · 250 MB
1,000 lookups by key
XOD JSON 2.353 ms
Flat · 250 MB
Size on disk
XOD Binary 70.56 MB
XOD 15 of 26 SQLite 9 LiteDB 2

Fastest engine per metric across the measured configurations, across XOD’s three storage formats. The cards below compare the selected XOD format with SQLite and LiteDB.

Format Compare

Flat table · 250 MB · 100k rows

One table, one indexed column — the shape of a list screen with search and paging. These are test sizes, not a limit.

15 runs · 5 engines · 8 metrics

Bulk load, 100k rows ↓ lower
XOD XML 1,183 ms
XOD JSON 2,546 ms
XOD Binary 4,269 ms
SQLite 1,607 ms
LiteDB 2,349 ms
What this means

Loading a large table in one go: an import, a restore, a first sync. One transaction per engine, payload included, fsync settings disclosed where they differ.

Open, then write a record ↓ lower
XOD XML 15.73 ms
XOD JSON 31.74 ms
XOD Binary 27.63 ms
SQLite 10.21 ms
LiteDB 2.827 ms
What this means

The cost of starting up and writing one record: what launching a desktop tool feels like. Fresh process, existing database, one insert and commit. Includes index load.

1,000 lookups by key ↓ lower
XOD XML 4.511 ms
XOD JSON 2.353 ms
XOD Binary 2.417 ms
SQLite 6.308 ms
LiteDB 40.64 ms
What this means

Fetching a thousand known records by id, as a detail screen or a batch job would. Random primary keys, warm process, index lookup plus row read per call.

20 queries on an index ↓ lower
XOD XML 17.41 ms
XOD JSON 8.539 ms
XOD Binary 7.96 ms
SQLite 38.85 ms
LiteDB 113.7 ms
What this means

Twenty ordinary filters returning 500 rows each: the list screens of a real application. Indexed secondary key, 10,000 rows hydrated in total; dominates list screens.

Jump deep into a result set ↓ lower
XOD XML 0.169 ms
XOD JSON 0.081 ms
XOD Binary 0.078 ms
SQLite 21.83 ms
LiteDB 142.5 ms
What this means

Opening a page near the end of a big table without reading everything before it. Offset pagination. Keyset pagination would make SQLite and LiteDB competitive again.

Batch edit and cleanup ↓ lower
XOD XML 50.2 ms
XOD JSON 165.3 ms
XOD Binary 201.4 ms
SQLite 4.173 ms
LiteDB 17.37 ms
What this means

A hundred records edited and a hundred removed, as a bulk action would. Read-modify-write per row, batched commit; XOD shares the batch.

Size on disk ↓ lower
XOD XML 253.8 MB
XOD JSON 325.9 MB
XOD Binary 70.56 MB
SQLite 394.8 MB
LiteDB 292.9 MB
What this means

How much space the database takes on disk after the load. All files in the database directory, including indexes and journal.

Peak memory ↓ lower
XOD XML 406.7 MB
XOD JSON 963.2 MB
XOD Binary 766.7 MB
SQLite 455.2 MB
LiteDB 692.3 MB
What this means

The most memory the process used while doing the work. Peak working set of an isolated worker process; includes the page cache.

Flat table · 1 GB · 400k rows

One table, one indexed column — the shape of a list screen with search and paging. These are test sizes, not a limit.

15 runs · 5 engines · 8 metrics

Bulk load, 100k rows ↓ lower
XOD XML 6,409 ms
XOD JSON 27,069 ms
XOD Binary 18,458 ms
SQLite 7,918 ms
LiteDB 9,175 ms
What this means

Loading a large table in one go: an import, a restore, a first sync. One transaction per engine, payload included, fsync settings disclosed where they differ.

Open, then write a record ↓ lower
XOD XML 27.89 ms
XOD JSON 185.8 ms
XOD Binary 44.11 ms
SQLite 5.48 ms
LiteDB 2.892 ms
What this means

The cost of starting up and writing one record: what launching a desktop tool feels like. Fresh process, existing database, one insert and commit. Includes index load.

1,000 lookups by key ↓ lower
XOD XML 5.259 ms
XOD JSON 2.756 ms
XOD Binary 2.743 ms
SQLite 9.499 ms
LiteDB 55.14 ms
What this means

Fetching a thousand known records by id, as a detail screen or a batch job would. Random primary keys, warm process, index lookup plus row read per call.

20 queries on an index ↓ lower
XOD XML 82.27 ms
XOD JSON 39.2 ms
XOD Binary 48.56 ms
SQLite 259 ms
LiteDB 426.5 ms
What this means

Twenty ordinary filters returning 500 rows each: the list screens of a real application. Indexed secondary key, 10,000 rows hydrated in total; dominates list screens.

Jump deep into a result set ↓ lower
XOD XML 1.271 ms
XOD JSON 0.203 ms
XOD Binary 0.209 ms
SQLite 630.1 ms
LiteDB 1,556 ms
What this means

Opening a page near the end of a big table without reading everything before it. Offset pagination. Keyset pagination would make SQLite and LiteDB competitive again.

Batch edit and cleanup ↓ lower
XOD XML 305.9 ms
XOD JSON 242.4 ms
XOD Binary 294.9 ms
SQLite 5.445 ms
LiteDB 19.23 ms
What this means

A hundred records edited and a hundred removed, as a bulk action would. Read-modify-write per row, batched commit; XOD shares the batch.

Size on disk ↓ lower
XOD XML 1,016 MB
XOD JSON 1,304 MB
XOD Binary 282.2 MB
SQLite 1,580 MB
LiteDB 1,172 MB
What this means

How much space the database takes on disk after the load. All files in the database directory, including indexes and journal.

Peak memory ↓ lower
XOD XML 1,442 MB
XOD JSON 3,108 MB
XOD Binary 2,782 MB
SQLite 642 MB
LiteDB 2,480 MB
What this means

The most memory the process used while doing the work. Peak working set of an isolated worker process; includes the page cache.

Related records · 10k customers

Customers, orders, order lines and products — inserted, loaded and deleted as a graph.

15 runs · 5 engines · 3 metrics

Insert customer graphs ↓ lower
XOD XML 4,340 ms
XOD JSON 7,046 ms
XOD Binary 6,502 ms
SQLite 680.6 ms
LiteDB 2,779 ms
What this means

Writing customers together with their orders and lines: related rows that must stay consistent. Normalized four-level graph; XOD inserts the object graph, SQLite uses one transaction.

Load 200 customer graphs ↓ lower
XOD XML 182.6 ms
XOD JSON 2,978 ms
XOD Binary 2,735 ms
SQLite 13.59 ms
LiteDB 211.5 ms
What this means

Two hundred detail screens, each loading a customer with orders and lines. Each load is customer + 5 orders + 20 lines + products.

Delete with cascade ↓ lower
XOD XML 77.3 ms
XOD JSON 971.2 ms
XOD Binary 680.6 ms
SQLite 12.76 ms
LiteDB 121.1 ms
What this means

Deleting customers and everything that belongs to them, without leaving orphan rows. Deletes customer, orders and order lines; validated by row counts after the run.

Related records · 40k customers

Customers, orders, order lines and products — inserted, loaded and deleted as a graph.

15 runs · 5 engines · 3 metrics

Insert customer graphs ↓ lower
XOD XML 15,850 ms
XOD JSON 86,916 ms
XOD Binary 27,366 ms
SQLite 2,353 ms
LiteDB 8,818 ms
What this means

Writing customers together with their orders and lines: related rows that must stay consistent. Normalized four-level graph; XOD inserts the object graph, SQLite uses one transaction.

Load 200 customer graphs ↓ lower
XOD XML 320.3 ms
XOD JSON 21,213 ms
XOD Binary 6,309 ms
SQLite 13.65 ms
LiteDB 225 ms
What this means

Two hundred detail screens, each loading a customer with orders and lines. Each load is customer + 5 orders + 20 lines + products.

Delete with cascade ↓ lower
XOD XML 157.8 ms
XOD JSON 8,685 ms
XOD Binary 1,962 ms
SQLite 21.8 ms
LiteDB 129.6 ms
What this means

Deleting customers and everything that belongs to them, without leaving orphan rows. Deletes customer, orders and order lines; validated by row counts after the run.

Readers and a writer · 250 MB · 100k rows

Eight threads reading while one thread writes, for five seconds, on the 100k-row table.

15 runs · 5 engines · 4 metrics

Reads per second, 8 threads ↑ higher
XOD XML 177,161 reads/s
XOD JSON 34,186 reads/s
XOD Binary 33,652 reads/s
SQLite 82,809 reads/s
LiteDB 115,616 reads/s
What this means

A busy service: eight threads reading while one thread writes. 5 s window, eight reader threads plus one writer.

Writes per second, 8 threads ↑ higher
XOD XML 5,071 writes/s
XOD JSON 505.7 writes/s
XOD Binary 153.2 writes/s
SQLite 4,883 writes/s
LiteDB 5,044 writes/s
What this means

How much writing still gets through while eight threads read. A reader-heavy workload can starve the writer; this is the number that shows it.

Typical read latency, 8 threads ↓ lower
XOD XML 5.9 µs
XOD JSON 5 µs
XOD Binary 5.1 µs
SQLite 18.6 µs
LiteDB 30 µs
What this means

Half of reads finish faster than this while eight threads are active. Median read latency under eight readers plus one writer.

Slow reads, 8 threads (p99) ↓ lower
XOD XML 320.5 µs
XOD JSON 3,855 µs
XOD Binary 6,959 µs
SQLite 592.7 µs
LiteDB 1,048 µs
What this means

One read in a hundred is slower than this under load: the tail users feel. 99th percentile read latency under eight readers plus one writer.

Method

What the benchmark guarantees.

  • Isolated process per run. A fresh worker for every engine, suite, scale and iteration.
  • Rotated order, repeated. Engines rotate each iteration; the page shows medians.
  • Same questions. One runner, one timer, the same POCOs and the same operations for every engine.
  • Answers validated. Counts, ids, graph shape and persisted values are checked, so a fast wrong answer fails the run.
  • Durability disclosed. XOD and SQLite run without fsync; LiteDB’s writes include its own, noted where it matters.
  • Page size disclosed. Every XOD database runs at 512 KB pages. Larger pages buy bulk-load time and cost mutations; smaller pages help relational reads on the document formats and roughly double bulk load. The trade-off is in the tuning notes.

What it does not prove

One machine, one storage volume, one set of shapes. Offset pagination flatters XOD and would look different with keyset paging. Reads on JSON and Binary pay for a page parse that XML does not. Treat the cards as questions to ask about your own workload, not as a verdict.

Where to check a number

The page builds from 1 committed result files. Each is named with the version and commit that produced it; the raw JSON is the record, this page is a rendering of it.