AcornDB 0.4.0
dotnet add package AcornDB --version 0.4.0
NuGet\Install-Package AcornDB -Version 0.4.0
<PackageReference Include="AcornDB" Version="0.4.0" />
<PackageVersion Include="AcornDB" Version="0.4.0" />
<PackageReference Include="AcornDB" />
paket add AcornDB --version 0.4.0
#r "nuget: AcornDB, 0.4.0"
#:package AcornDB@0.4.0
#addin nuget:?package=AcornDB&version=0.4.0
#tool nuget:?package=AcornDB&version=0.4.0
π° AcornDB

AcornDB is a lightweight, reactive, embedded database for .NET β for devs whoβd rather ship products than pay $400/month to store 5MB of JSON.
πΏοΈ Nutty by design. Practical by necessity.
π Why AcornDB Exists
Most apps donβt need Cosmos DB, Kafka, or Redis.
They need:
- Fast, local-first persistence
- Simple per-tenant or per-user storage
- Offline support + syncing that doesnβt make you cry
AcornDB is for:
- Desktop apps
- IoT devices
- Mobile backends
- CLI tools
- Serverless & edge workloads
- And yes β you with the single-user SaaS that stores 10KB per user
π Core Concepts
| Term | What It Means |
|---|---|
Tree<T> |
A local document collection β your "embedded table" |
Nut<T> |
An object wrapped with metadata (TTL, version, timestamp) |
ITrunk<T> |
Storage abstraction: File, Memory, Azure Blob, or versioned |
Branch |
A connection to a remote Tree via HTTP |
Tangle |
A live sync session between two Trees |
Grove |
A set of Trees managed + synced together |
Canopy |
(Internal) sync orchestrator living inside the Grove |
Stash/Crack/Toss |
Insert, read, and delete objects β squirrel-style verbs |
Shake() |
Manual sync trigger |
π§ Features
| Feature | Description |
|---|---|
π° Stash, Crack, Toss |
Drop-in persistence with zero boilerplate |
| π― Auto-ID Detection | Stash without explicit IDs - automatically uses Id or Key properties |
π‘οΈ Nut<T> |
Versioned, timestamped, TTL-wrapped records |
π Branch, Tangle, Grove |
Live sync between Trees, across machines |
πͺ’ Entangle<T>() |
Sync trees via HTTP or in-process without a server |
π© Oversee<T>() |
One-liner to monitor remote branches |
βοΈ Squabble() + Judge |
Built-in conflict resolution with custom override |
π§ INutment<TKey> |
Typed ID interface for strongly keyed documents |
π§Ή SmushNow() |
Manual compaction of log-based storage |
π°οΈ ExportChanges() / ImportChanges() |
Manual sync if you're old-school |
π² Grove.Plant<T>() |
Auto-creates and registers a Tree<T> |
| π Totem-based auth (coming) | Because why not woodland-themed security? |
π§ͺ Getting Started
# Coming soon to NuGet:
dotnet add package AcornDB
Quick Example
// Define your model with an Id property
public class User
{
public string Id { get; set; } = Guid.NewGuid().ToString();
public string Name { get; set; }
}
// Create a Tree (defaults to FileTrunk - no config needed!)
var tree = new Tree<User>();
// Stash without explicit ID (auto-detected from Id property)
tree.Stash(new User { Name = "Squirrelius Maximus" });
// Crack it back
var user = tree.Crack("...");
With Sync
// Set up syncing with a Grove
var grove = new Grove();
grove.Plant(tree);
grove.Oversee<User>(new Branch("http://localhost:5000")); // auto-sync!
tree.Shake(); // optionally force a sync
β¨ What Makes AcornDB Simple
π― Auto-ID Detection
No more specifying IDs twice. If your model has an Id or Key property, AcornDB finds it automatically:
public class Task
{
public string Id { get; set; } = Guid.NewGuid().ToString();
public string Title { get; set; }
}
var tree = new Tree<Task>();
tree.Stash(new Task { Title = "Learn AcornDB" }); // ID auto-detected!
πͺ΅ Optional Trunk (Defaults to FileTrunk)
Skip the boilerplate. Trees default to file-based storage:
// Before
var tree = new Tree<User>(new FileTrunk<User>("data/User"));
// Now
var tree = new Tree<User>(); // Automatically uses FileTrunk!
πͺ’ In-Process Sync
Connect trees directly without HTTP:
var tree1 = new Tree<User>();
var tree2 = new Tree<User>(new MemoryTrunk<User>());
tree1.Entangle(tree2); // No server needed!
π Shared Storage Sync
Multiple processes? Just point to the same directory:
// Process 1
var tree1 = new Tree<User>(new FileTrunk<User>("shared/data"));
tree1.Stash(new User { Id = "alice", Name = "Alice" });
// Process 2
var tree2 = new Tree<User>(new FileTrunk<User>("shared/data"));
var alice = tree2.Crack("alice"); // Already there!
ποΈ Storage Abstraction (Trunks)
AcornDB uses Trunks to abstract storage β swap your backend without touching your Tree code.
Available Trunks
| Trunk | Use Case | History | Sync |
|---|---|---|---|
FileTrunk<T> |
Simple file-based storage | β | β |
MemoryTrunk<T> |
Fast in-memory (great for tests) | β | β |
DocumentStoreTrunk<T> |
Full versioning & time-travel | β | β |
AzureTrunk<T> |
Azure Blob Storage | β | β |
Examples
// π FileTrunk (DEFAULT): Simple, no history
var fileTree = new Tree<User>(); // Defaults to FileTrunk!
fileTree.Stash(new User { Id = "alice", Name = "Alice" }); // Auto-ID
// Or explicit path
var customTree = new Tree<User>(new FileTrunk<User>("data/users"));
// πΎ MemoryTrunk: Fast, non-durable
var memTree = new Tree<User>(new MemoryTrunk<User>());
memTree.Stash(new User { Id = "bob", Name = "Bob" });
// π DocumentStoreTrunk: Full history & versioning
var docTree = new Tree<User>(new DocumentStoreTrunk<User>("data/versioned"));
docTree.Stash(new User { Id = "charlie", Name = "Charlie v1" });
docTree.Stash(new User { Id = "charlie", Name = "Charlie v2" });
var history = docTree.GetHistory("charlie"); // Get previous versions!
// Returns: 1 previous version ("Charlie v1")
// π Export/Import between trunks
var sourceTrunk = new FileTrunk<User>("data/source");
var targetTrunk = new AzureTrunk<User>("connection-string");
targetTrunk.ImportChanges(sourceTrunk.ExportChanges()); // Migrate!
Time-Travel with DocumentStoreTrunk
var tree = new Tree<Product>(new DocumentStoreTrunk<Product>("data/products"));
tree.Stash(new Product { Id = "widget", Name = "Widget v1.0" });
tree.Stash(new Product { Id = "widget", Name = "Widget v2.0" });
tree.Stash(new Product { Id = "widget", Name = "Widget v3.0" });
var current = tree.Crack("widget"); // "Widget v3.0"
var history = tree.GetHistory("widget"); // ["Widget v1.0", "Widget v2.0"]
// All changes stored in append-only log: data/products/changes.log
NotSupportedException Pattern
Trunks that don't support history throw NotSupportedException:
var memTree = new Tree<User>(new MemoryTrunk<User>());
try {
var history = memTree.GetHistory("user1");
} catch (NotSupportedException) {
Console.WriteLine("MemoryTrunk doesn't support history!");
}
Feature Detection with ITrunkCapabilities
Check trunk features without exceptions:
var trunk = new MemoryTrunk<User>();
var caps = trunk.GetCapabilities();
Console.WriteLine($"Trunk: {caps.TrunkType}");
Console.WriteLine($"History: {caps.SupportsHistory}");
Console.WriteLine($"Sync: {caps.SupportsSync}");
Console.WriteLine($"Durable: {caps.IsDurable}");
Console.WriteLine($"Async: {caps.SupportsAsync}");
// Use extension methods for quick checks
if (trunk.CanGetHistory())
{
var history = trunk.GetHistory("user1");
}
else
{
Console.WriteLine("This trunk doesn't support history");
}
Capability Matrix:
| Trunk | History | Sync | Durable | Async |
|---|---|---|---|---|
| FileTrunk | β | β | β | β |
| MemoryTrunk | β | β | β | β |
| DocumentStoreTrunk | β | β | β | β |
| AzureTrunk | β | β | β | β |
π Sync with TreeBark
TreeBark is the HTTP sync server for AcornDB - it exposes Trees over REST endpoints.
Quick Start Sync Server
// Server side (AcornSyncServer project)
var grove = new Grove();
grove.Plant(new Tree<User>(new FileTrunk<User>("data/users")));
grove.Plant(new Tree<Product>(new FileTrunk<Product>("data/products")));
// Run with: dotnet run --project AcornSyncServer
// TreeBark starts on http://localhost:5000
TreeBark REST API
| Endpoint | Method | Description |
|---|---|---|
/ |
GET | Health check + API docs |
/bark/{treeName}/stash |
POST | Stash a nut to remote tree |
/bark/{treeName}/crack/{id} |
GET | Crack a nut from remote tree |
/bark/{treeName}/toss/{id} |
DELETE | Toss a nut from remote tree |
/bark/{treeName}/export |
GET | Export all nuts from tree |
/bark/{treeName}/import |
POST | Import nuts into tree |
Client-Side Sync with Branch
// Client side - connect to remote TreeBark server
var localTree = new Tree<User>(new MemoryTrunk<User>());
var branch = new Branch("http://localhost:5000/bark/User");
// Manual push with auto-ID
var alice = new User { Id = "alice", Name = "Alice" };
localTree.Stash(alice);
branch.TryPush(alice.Id, localTree.Crack(alice.Id));
// Manual pull
await branch.ShakeAsync(localTree); // Pulls all remote changes
// Auto-sync with Tangle
var grove = new Grove();
grove.Plant(localTree);
grove.Entangle<User>(branch, "sync-session-1"); // Auto-syncs on every stash!
Full Sync Example
Server (dotnet run --project AcornSyncServer):
var grove = new Grove();
grove.Plant(new Tree<User>(new DocumentStoreTrunk<User>("data/users")));
// TreeBark running on http://localhost:5000
Client 1 (Desktop App):
var tree1 = new Tree<User>(new FileTrunk<User>("client1/users"));
var branch = new Branch("http://localhost:5000");
var alice = new User { Id = "alice", Name = "Alice" };
tree1.Stash(alice); // Auto-ID detection
branch.TryPush(alice.Id, tree1.Crack(alice.Id)); // Syncs to server
Client 2 (Mobile App):
var tree2 = new Tree<User>(new MemoryTrunk<User>());
var branch = new Branch("http://localhost:5000");
await branch.ShakeAsync(tree2); // Pulls "alice" from server!
var alice = tree2.Crack("alice"); // "Alice" is now local
π° AcornDB Visualizer - Web UI
Explore your Grove with an interactive web dashboard!
cd AcornVisualizer
dotnet run
# Open browser to http://localhost:5100
Features:
- π Live Dashboard - Real-time stats on trees, nuts, and operations
- π³ Tree Explorer - Browse all trees with detailed metadata
- π Graph View - Interactive circular node visualization
- π Nut Inspector - View payloads, timestamps, and history
- βοΈ Trunk Info - See capabilities (history, sync, durable, async)
- π Auto-Refresh - Updates every 5 seconds
Perfect for:
- Local development and debugging
- Visual demos and presentations
- Understanding your grove structure
- Monitoring nut operations
See AcornVisualizer/README.md for full documentation.
π² Same-Host Sync (No Server Required!)
For processes on the same host, AcornDB offers two simple sync strategies:
β Option 1: Shared FileTrunk (Simplest!)
Just point both trees to the same directory:
// Process 1
var tree1 = new Tree<User>(new FileTrunk<User>("shared/users"));
tree1.Stash(new User { Id = "alice", Name = "Alice" });
// Process 2
var tree2 = new Tree<User>(new FileTrunk<User>("shared/users"));
var alice = tree2.Crack("alice"); // β
Automatically synced!
Zero setup. Zero config. Just works.
πͺ’ Option 2: In-Process Tree Entanglement
Sync two trees directly without HTTP:
var tree1 = new Tree<User>();
var tree2 = new Tree<User>(new MemoryTrunk<User>());
tree1.Entangle(tree2); // Direct tree-to-tree sync!
tree1.Stash(new User { Id = "bob", Name = "Bob" });
// Automatically synced to tree2 via InProcessBranch
Perfect for in-memory scenarios or testing.
When to Use Each Sync Strategy
| Scenario | Recommended Approach |
|---|---|
| Same host, multiple processes | π’ Shared FileTrunk |
| Same process, different trees | π’ In-Process Entanglement |
| Different hosts | π’ TreeBark HTTP |
| Desktop apps with multiple instances | π’ Shared FileTrunk |
| Mobile to cloud | π’ TreeBark HTTP |
| Distributed systems | π’ TreeBark HTTP |
| CLI tools | π’ Shared FileTrunk |
| Complex multi-process with separate storage | π’ File System Sync Hub |
π§± Project Structure
| Folder | Purpose |
|---|---|
AcornDB |
Core engine (Tree, Nut, Trunk, Tangle) |
AcornSyncServer |
TreeBark: HTTP sync server (REST API) |
AcornVisualizer |
Web UI: Interactive grove dashboard |
AcornDB.Canopy |
SignalR hub + visualizations |
AcornDB.Demo |
Examples showcasing all features |
SyncDemo |
Live multi-client sync demonstration |
AcornDB.Test |
xUnit tests (26 passing) |
π§ What's Coming
- π Auth: Totems, ForageRights, Critters, and BarkCodes
- π‘ Mesh sync: Peer-to-peer Tangle networks
- π¦ NuGet & CLI: Install and create projects with
acorn new - π AutoRecovery: Offline-first sync queue with resilience
- π§ͺ Playgrounds: Sample apps, code snippets, and demos
- π¨ Visualizer Enhancements: Real-time updates, diff viewer, dark mode
π² The Acorn Ethos
πΏοΈ Serious software. Zero seriousness.
AcornDB was born out of frustration with bloated infra, soulless APIs, and naming things like DataClientServiceManagerFactoryFactory.
So we built something better β not just in function, but in vibe.
We believe:
- Developers deserve fun.
- Tools should make you smile, not sigh.
- Syncing JSON should not require Kubernetes and a degree in wizardry.
- "Toss the nut and shake the tree" should be valid engineering advice.
If youβve ever rage-quit YAML, yelled at Terraform, or cried syncing offline-first apps β
welcome. Youβve found your grove.
π° Stash boldly. Crack with confidence. And never, ever apologize for getting a little squirrelly.
𦦠Built with acorns and sarcasm
Weβre tired of YAML. Tired of cloud bills. Tired of DataServiceFactoryClientFactoryFactory.
So we built AcornDB.
If you fork this, star it, or build something fun β send us your weirdest squirrel pun.
πΏοΈ Stay nutty.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net8.0
- Azure.Storage.Blobs (>= 12.19.1)
- LibGit2Sharp (>= 0.31.0)
- Newtonsoft.Json (>= 13.0.4)
- System.Reactive (>= 6.1.0)
NuGet packages (3)
Showing the top 3 NuGet packages that depend on AcornDB:
| Package | Downloads |
|---|---|
|
AcornDB.Canopy
🌲 AcornDB.Canopy - SignalR hub and real-time visualization extensions for AcornDB. Adds Hardwood HTTP server, live sync orchestration, and real-time grove monitoring capabilities. |
|
|
AcornDB.Persistence.Cloud
🌰 Cloud storage providers for AcornDB - AWS S3, Azure Blob Storage, and other cloud-based trunk implementations. Separate package to keep core AcornDB lean. |
|
|
AcornDB.Persistence.RDBMS
🌰 RDBMS storage providers for AcornDB - SQLite, SQL Server, PostgreSQL, MySQL trunk implementations for relational database persistence. |
GitHub repositories
This package is not used by any popular GitHub repositories.
v0.4.0: NEW GitHubTrunk (Git-as-database with full version history), Nursery system for dynamic trunk discovery, trunk factory pattern, fluent trunk configuration API. Separate persistence packages: AcornDB.Persistence.Cloud (S3, Azure Blob) and AcornDB.Persistence.RDBMS (SQLite, SQL Server, PostgreSQL, MySQL).