![]() |
VOOZH | about |
dotnet add package ZoneTree --version 1.9.2
NuGet\Install-Package ZoneTree -Version 1.9.2
<PackageReference Include="ZoneTree" Version="1.9.2" />
<PackageVersion Include="ZoneTree" Version="1.9.2" />Directory.Packages.props
<PackageReference Include="ZoneTree" />Project file
paket add ZoneTree --version 1.9.2
#r "nuget: ZoneTree, 1.9.2"
#:package ZoneTree@1.9.2
#addin nuget:?package=ZoneTree&version=1.9.2Install as a Cake Addin
#tool nuget:?package=ZoneTree&version=1.9.2Install as a Cake Tool
The engine beneath serious .NET data systems.
ZoneTree is a high-performance storage engine for ordered, persistent data. It is built for teams creating databases, indexes, search systems, queues, event stores, local-first applications, and custom data platforms in the .NET ecosystem.
👁 NuGet
👁 Downloads
👁 License
👁 Platform
👁 Build
Modern data systems are not built on features alone. They are built on storage layers that shape performance, reliability, and product architecture.
.NET has excellent databases and frameworks, but very few native storage engines that can be used as a foundation for building new data systems.
ZoneTree fills that layer.
It gives .NET systems a fast, programmable foundation for ordered data that must be written quickly, read predictably, persisted reliably, and shaped around the product instead of forcing the product into a fixed database model.
ZoneTree gives you the core pieces expected from a serious storage engine:
ZoneTree can be used directly as an ordered key-value database, or as the storage foundation for higher-level systems.
dotnet add package ZoneTree
using ZoneTree;
using var zoneTree = new ZoneTreeFactory<int, string>()
.SetDataDirectory("data/my-zone-tree")
.OpenOrCreate();
zoneTree.Upsert(1, "Hello ZoneTree");
if (zoneTree.TryGet(1, out var value))
{
Console.WriteLine(value);
}
ZoneTree stores keys in order. This makes it suitable for indexes, prefix layouts, time-series patterns, range scans, and custom data models.
using var iterator = zoneTree.CreateIterator();
iterator.Seek(100);
while (iterator.Next())
{
Console.WriteLine($"{iterator.CurrentKey}: {iterator.CurrentValue}");
}
Reverse iteration is also supported:
using var iterator = zoneTree.CreateReverseIterator();
iterator.Seek(1000);
while (iterator.Next())
{
Console.WriteLine($"{iterator.CurrentKey}: {iterator.CurrentValue}");
}
ZoneTree provides atomic operations for read-modify-write scenarios across LSM-tree segments.
zoneTree.TryAtomicAddOrUpdate(
key: 42,
valueToAdd: 1,
valueUpdater: (ref int value) =>
{
value++;
return true;
},
result: (in int value, long opIndex, OperationResult result) =>
{
Console.WriteLine($"{result}: {value} at {opIndex}");
});
Plain Upsert is the fastest write path. Atomic methods are synchronized with other atomic methods and are intended for operations that must read, decide, and write as one logical action.
For normal concurrent writes, use the regular write APIs. They are designed for high-throughput use. Choose atomic methods only when the new value depends on the existing value.
| Need | Use |
|---|---|
| Set or replace a value | Upsert |
| Add only if the key does not exist | TryAdd |
| Delete a key if it exists | TryDelete |
| Write a deletion marker without checking existence | ForceDelete |
| Increment, append, compare-and-set, or update from the current value | Atomic methods |
| Coordinate changes across multiple keys | Transactions |
You can mix these write modes in the same ZoneTree. For example, hot counter keys can use atomic read-modify-write operations, while ordinary records continue to use fast Upsert. This lets each workflow pay only for the coordination it needs.
For coordinated multi-key changes, open a transactional ZoneTree.
using var zoneTree = new ZoneTreeFactory<int, string>()
.SetDataDirectory("data/transactional-zone-tree")
.OpenOrCreateTransactional();
var tx = zoneTree.BeginTransaction();
zoneTree.Upsert(tx, 1, "first");
zoneTree.Upsert(tx, 2, "second");
var result = zoneTree.PrepareAndCommit(tx);
Console.WriteLine(result.Result);
Use transactions when your data model requires coordination across multiple keys. For simple high-throughput writes, the non-transactional API is usually the better path.
ZoneTree uses deletion markers. This is common in LSM-tree based storage engines: a delete is written first, and obsolete data is removed later during compaction.
For many primitive and nullable types, ZoneTree can provide default deletion behavior. You can also define your own delete marker.
The same mechanism can be used for TTL-style records. Store an expiration timestamp in the value, and make the delete predicate return true when the value has expired. ZoneTree will treat expired records like deleted records, and maintenance/compaction can remove obsolete data later.
using var zoneTree = new ZoneTreeFactory<int, int>()
.SetDataDirectory("data/deletable")
.SetIsDeletedDelegate((in int key, in int value) => value == -1)
.SetMarkValueDeletedDelegate((ref int value) => value = -1)
.OpenOrCreate();
zoneTree.Upsert(42, 100);
zoneTree.TryDelete(42, out var opIndex);
If your database does not need deletions and you want to store default values normally, deletion can be disabled:
using var zoneTree = new ZoneTreeFactory<int, int>()
.DisableDeletion()
.OpenOrCreate();
ZoneTree uses an LSM-tree architecture. Writes first enter a mutable segment and are later moved, merged, and compacted into persistent segments.
For long-running applications, use the maintainer to run background maintenance.
using var zoneTree = new ZoneTreeFactory<int, string>()
.SetDataDirectory("data/app")
.OpenOrCreate();
using var maintainer = zoneTree.CreateMaintainer();
zoneTree.Upsert(1, "value");
// Before shutdown, wait for background work if needed.
maintainer.WaitForBackgroundThreads();
Maintenance behavior can be tuned for different workloads.
ZoneTree is designed for datasets larger than memory. It does not need to load the whole database into RAM.
Memory usage mainly comes from the active mutable segment, frozen in-memory segments waiting for merge, disk block cache, sparse indexes, iterators that pin active segments, and temporary buffers used during merge or WAL processing.
The most important write-side memory control is the mutable segment size. By default, ZoneTree starts moving a mutable segment toward disk after 1_000_000 records. This is a good default for small keys and values, but applications storing large strings, documents, or payload objects should lower the mutable segment record limit to keep memory usage predictable.
ZoneTree is built as a native .NET storage engine and uses the .NET garbage collector as part of its design. The GC is highly optimized for modern application workloads and helps keep ZoneTree simple, safe, and fast without requiring manual memory management.
When observing memory usage, remember that .NET may keep freed memory available for reuse instead of returning it to the operating system immediately. Process memory can remain high even after segments are merged or released, so use .NET memory diagnostics when you need to measure live ZoneTree data precisely.
using var zoneTree = new ZoneTreeFactory<int, string>()
.SetDataDirectory("data/app")
.SetMutableSegmentMaxItemCount(10_000)
.OpenOrCreate();
For read-heavy workloads, memory is mostly shaped by cache behavior and the active working set. For write-heavy workloads, memory is mostly shaped by mutable segment size and how quickly maintenance can move frozen segments to disk.
ZoneTree persists data through disk segments and write-ahead logs. Recent writes enter the mutable segment and are protected according to the configured WAL mode. Maintenance later moves and merges data into disk segments.
ZoneTree uses async compressed WAL by default. It is the recommended starting point for most persistent databases because it keeps WAL protection enabled while preserving very high write throughput.
| Need | Consider |
|---|---|
| Default safe high-throughput WAL mode | Async compressed WAL |
| Synchronous compressed WAL acknowledgment | Sync compressed WAL |
| Simplest synchronous WAL path | Sync WAL |
| Intentional no-WAL boundary for cache/temp/rebuildable data | No WAL |
Disk segments can also use compression and different segment layouts. These options help tune disk space, read patterns, merge behavior, and file-size boundaries.
For long-running services, ZoneTree also supports live backup for built-in non-transactional trees. Live backup creates complete backup generations while the tree remains open for reads and writes, and local backup generations can be restored through ZoneTreeFactory.
ZoneTree is built for high-throughput workloads.
The repository includes benchmark results covering large insert, load, merge, and iteration scenarios across different key/value types and write-ahead log modes.
In the included insert benchmarks, ZoneTree performs significantly faster than RocksDB on the tested workloads.
| Insert Benchmarks | 1M | 2M | 3M | 10M |
|---|---|---|---|---|
| int-int ZoneTree async-compressed WAL | 267 ms | 464 ms | 716 ms | 2693 ms |
| int-int ZoneTree sync-compressed WAL | 834 ms | 1617 ms | 2546 ms | 8642 ms |
| int-int ZoneTree sync WAL | 2742 ms | 5533 ms | 8242 ms | 27497 ms |
| str-str ZoneTree async-compressed WAL | 892 ms | 1833 ms | 2711 ms | 9443 ms |
| str-str ZoneTree sync-compressed WAL | 1752 ms | 3397 ms | 5070 ms | 19153 ms |
| str-str ZoneTree sync WAL | 3488 ms | 7002 ms | 10483 ms | 38727 ms |
| int-int RocksDB sync-compressed WAL | 8059 ms | 16188 ms | 23599 ms | 61947 ms |
| str-str RocksDB sync-compressed WAL | 8215 ms | 16146 ms | 23760 ms | 72491 ms |
Performance depends on workload and configuration, including:
See the benchmark results:
Benchmark results vary with data shape, configuration, and hardware. Review the full benchmark file for details.
ZoneTree is designed from the ground up as a storage-engine foundation for scalable systems. It is not a distributed database by itself; instead, it provides the ordered keyspace, durability controls, iterators, operation indexes, transactions, and maintenance hooks needed to build partitioned, replicated, or domain-specific data platforms above it.
It can power:
The engine provides the ordered, persistent core; your product defines the model above it.
ZoneTree.FullTextSearch is a full-text search library built on ZoneTree.
It provides indexing and search capabilities for applications that need fast text search over ZoneTree-backed storage.
Repository:
Official documentation:
Building production systems on ZoneTree?
Official support is available for organizations that want direct guidance on architecture, performance, reliability, storage design, troubleshooting, and production readiness.
Support engagements can include prioritized issue handling, prioritized bug fixes for confirmed defects, private technical communication, upgrade guidance, and scheduled advisory sessions.
Start here:
ZoneTree is open-source infrastructure for the .NET ecosystem.
Sponsorship helps sustain engineering work behind the project: performance, testing, documentation, benchmarks, integrations, and long-term stability.
Sponsor ZoneTree:
Contributions are welcome.
Good contributions include:
Before large changes, please open an issue or discussion first.
ZoneTree is licensed under the MIT License.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net9.0 net9.0 is compatible. net9.0-android net9.0-android was computed. net9.0-browser net9.0-browser was computed. net9.0-ios net9.0-ios was computed. net9.0-maccatalyst net9.0-maccatalyst was computed. net9.0-macos net9.0-macos was computed. net9.0-tvos net9.0-tvos was computed. net9.0-windows net9.0-windows was computed. net10.0 net10.0 is compatible. net10.0-android net10.0-android was computed. net10.0-browser net10.0-browser was computed. net10.0-ios net10.0-ios was computed. net10.0-maccatalyst net10.0-maccatalyst was computed. net10.0-macos net10.0-macos was computed. net10.0-tvos net10.0-tvos was computed. net10.0-windows net10.0-windows was computed. |
Showing the top 5 NuGet packages that depend on ZoneTree:
| Package | Downloads |
|---|---|
|
DifferentialComputeDotNet.Core
Package Description |
|
|
ZoneTree.FullTextSearch
ZoneTree.FullTextSearch is an open-source library that extends ZoneTree to provide efficient full-text search capabilities. It offers a fast, embedded search engine suitable for applications that require high performance and do not rely on external databases. |
|
|
ManagedCode.Database.ZoneTree
Repository for ZoneTree |
|
|
ManagedCode.ZoneTree.BlobFileSystem
Azure Blob FileSystem for ZoneTree |
|
|
Bielu.PersistentQueues.Storage.ZoneTree
ZoneTree storage provider for Bielu.PersistentQueues |
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.9.2 | 121 | 6/13/2026 |
| 1.9.1 | 94 | 6/13/2026 |
| 1.9.0 | 99 | 6/13/2026 |
| 1.8.9 | 125 | 6/11/2026 |
| 1.8.8 | 101 | 6/10/2026 |
| 1.8.7 | 227 | 6/8/2026 |
| 1.8.6 | 9,531 | 6/14/2025 |
| 1.8.5 | 12,141 | 1/18/2025 |
| 1.8.4 | 1,036 | 11/14/2024 |
| 1.8.3 | 509 | 10/16/2024 |
| 1.8.2 | 2,127 | 9/7/2024 |
| 1.8.1 | 311 | 9/7/2024 |
| 1.8.0 | 329 | 9/1/2024 |
| 1.7.9 | 335 | 8/30/2024 |
| 1.7.8 | 287 | 8/30/2024 |
| 1.7.7 | 393 | 8/24/2024 |
| 1.7.6 | 352 | 8/17/2024 |
| 1.7.5 | 305 | 8/17/2024 |
| 1.7.4 | 302 | 8/11/2024 |
| 1.7.3 | 302 | 8/10/2024 |