OxiDB now has first-class .NET support with three NuGet packages: a pure managed TCP client, an embedded FFI client that runs the database in-process, and a full Entity Framework Core provider that supports both modes. All three target .NET 10.0 and are available for download from the downloads page.

Three Packages, One Interface

The key design principle is a shared IOxiDbClient interface. Both the TCP and embedded clients implement the same interface, which means you can swap between network and embedded mode without changing your application code:

PackageModeSizeUse Case
OxiDb.Client.TcpNetwork client16 KBConnect to a remote OxiDB server
OxiDb.Client.EmbeddedIn-process FFI2.3 MBEmbed the database directly in your app
OxiDb.EntityFrameworkCoreEF Core provider23 KBUse OxiDB with LINQ, change tracking, migrations

OxiDb.Client.Tcp — Pure Managed TCP Client

A lightweight, zero-dependency TCP client that speaks OxiDB's length-prefixed protocol. Thread-safe via SemaphoreSlim, fully async, and supports both JSON and OxiWire binary encoding.

Connect

using OxiDb.Client.Tcp;

// Basic connection
var client = await OxiDbTcpClient.ConnectAsync("127.0.0.1", 4444);

// With SCRAM-SHA-256 authentication
var client = await OxiDbTcpClient.ConnectAsync("127.0.0.1", 4444, "admin", "secret");

// Enable OxiWire binary protocol for faster encoding
client.UseOxiWire();

CRUD Operations

// Insert
await client.InsertAsync("products", new { name = "Widget", price = 19.99, category = "tools" });

// Batch insert
await client.InsertManyAsync("products", new[] {
    new { name = "Gadget", price = 29.99, category = "electronics" },
    new { name = "Gizmo", price = 9.99, category = "tools" }
});

// Find with query operators
var expensive = await client.FindAsync("products", new { price = new { $gt = 15 } });

// Find one
var widget = await client.FindOneAsync("products", new { name = "Widget" });

// Update
await client.UpdateAsync("products",
    new { category = "tools" },                        // filter
    new { $set = new { category = "hand-tools" } }     // update
);

// Delete
await client.DeleteAsync("products", new { price = new { $lt = 10 } });

// Count
var count = await client.CountAsync("products", new { category = "electronics" });

Indexes

await client.CreateIndexAsync("products", "category");
await client.CreateUniqueIndexAsync("products", "sku");
await client.CreateCompositeIndexAsync("products", new[] { "category", "price" });
var indexes = await client.ListIndexesAsync("products");

Aggregation

var pipeline = new object[] {
    new { $match = new { category = "electronics" } },
    new { $group = new { _id = "$brand", total = new { $sum = "$price" } } },
    new { $sort = new { total = -1 } },
    new { $limit = 10 }
};
var results = await client.AggregateAsync("products", pipeline);

Transactions

// Manual transaction
await client.BeginTransactionAsync();
try {
    await client.InsertAsync("orders", new { item = "Widget", qty = 5 });
    await client.UpdateAsync("inventory", new { item = "Widget" }, new { $inc = new { qty = -5 } });
    await client.CommitTransactionAsync();
} catch {
    await client.RollbackTransactionAsync();
    throw;
}

// Or use the convenience wrapper
await client.WithTransactionAsync(async () => {
    await client.InsertAsync("orders", new { item = "Widget", qty = 5 });
    await client.UpdateAsync("inventory", new { item = "Widget" }, new { $inc = new { qty = -5 } });
});

OxiDb.Client.Embedded — In-Process Database

Run OxiDB directly inside your .NET process with zero network overhead. The embedded client wraps the native Rust library via P/Invoke (C FFI), giving you the full power of the OxiDB engine without a separate server process.

using OxiDb.Client.Embedded;

// Open a database at a file path
using var db = OxiDbEmbeddedClient.Open("./oxidb_data");

// Or open with AES-GCM transparent encryption
using var db = OxiDbEmbeddedClient.OpenEncrypted("./oxidb_data", "./encryption.key");

// Same API as TCP client — IOxiDbClient interface
await db.InsertAsync("users", new { name = "Alice", email = "[email protected]" });
var users = await db.FindAsync("users", new { name = "Alice" });

The embedded package includes native runtimes for:

  • macOSliboxidb_embedded_ffi.dylib (ARM64 + x86_64)
  • Linuxliboxidb_embedded_ffi.so (x86_64, musl static)
  • Windowsoxidb_embedded_ffi.dll (x86_64)

The native library is automatically selected at runtime based on your platform. No manual configuration needed.

When to Use Embedded vs TCP

EmbeddedTCP
LatencyMicroseconds (in-process)Milliseconds (network)
DeploymentSingle process, no serverSeparate server process
ConcurrencySingle process onlyMultiple clients
Use caseDesktop apps, CLI tools, testsWeb apps, microservices
AuthenticationNot needed (in-process)SCRAM-SHA-256
EncryptionAES-GCM at storage layerTLS + AES-GCM

OxiDb.EntityFrameworkCore — EF Core Provider

The crown jewel: a full Entity Framework Core provider that lets you use OxiDB with LINQ queries, change tracking, dependency injection, and all the EF Core patterns .NET developers already know.

Setup

using OxiDb.EntityFrameworkCore;

// TCP mode
services.AddDbContext<AppDbContext>(options =>
    options.UseOxiDb("127.0.0.1", 4444)
);

// With authentication
services.AddDbContext<AppDbContext>(options =>
    options.UseOxiDb("127.0.0.1", 4444, username: "admin", password: "secret")
);

// Embedded mode
services.AddDbContext<AppDbContext>(options =>
    options.UseOxiDbEmbedded("./oxidb_data")
);

// Embedded with encryption
services.AddDbContext<AppDbContext>(options =>
    options.UseOxiDbEmbedded("./oxidb_data", encryptionKeyPath: "./encryption.key")
);

Define Your Model

public class AppDbContext : DbContext
{
    public DbSet<Product> Products => Set<Product>();
    public DbSet<Order> Orders => Set<Order>();

    public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { }
}

public class Product
{
    public string Id { get; set; }
    public string Name { get; set; }
    public decimal Price { get; set; }
    public string Category { get; set; }
}

public class Order
{
    public string Id { get; set; }
    public string ProductId { get; set; }
    public int Quantity { get; set; }
    public DateTime CreatedAt { get; set; }
}

LINQ Queries

// All products in a category
var electronics = await db.Products
    .Where(p => p.Category == "Electronics")
    .OrderBy(p => p.Price)
    .ToListAsync();

// Find by ID
var product = await db.Products.FindAsync("abc123");

// Count with filter
var count = await db.Products.CountAsync(p => p.Price > 100);

// First or default
var cheapest = await db.Products
    .OrderBy(p => p.Price)
    .FirstOrDefaultAsync();

// Pagination
var page = await db.Products
    .Skip(20)
    .Take(10)
    .ToListAsync();

Change Tracking

// Insert
db.Products.Add(new Product { Name = "Widget", Price = 19.99m, Category = "Tools" });
await db.SaveChangesAsync();

// Update — only modified fields are sent
var product = await db.Products.FindAsync("abc123");
product.Price = 24.99m;
await db.SaveChangesAsync();  // sends: $set { price: 24.99 }

// Delete
db.Products.Remove(product);
await db.SaveChangesAsync();

Transactions

using var transaction = await db.Database.BeginTransactionAsync();
try
{
    db.Orders.Add(new Order { ProductId = "abc123", Quantity = 5 });
    var product = await db.Products.FindAsync("abc123");
    product.Stock -= 5;
    await db.SaveChangesAsync();
    await transaction.CommitAsync();
}
catch
{
    await transaction.RollbackAsync();
    throw;
}

ASP.NET Minimal API Example

A complete REST API in under 30 lines:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddDbContext<ShopContext>(options =>
    options.UseOxiDb(
        builder.Configuration["OxiDb:Host"] ?? "127.0.0.1",
        int.Parse(builder.Configuration["OxiDb:Port"] ?? "4444")
    )
);

var app = builder.Build();

app.MapGet("/products", async (ShopContext db) =>
    await db.Products.ToListAsync()
);

app.MapGet("/products/{id}", async (ShopContext db, string id) =>
    await db.Products.FindAsync(id) is Product p ? Results.Ok(p) : Results.NotFound()
);

app.MapPost("/products", async (ShopContext db, Product product) =>
{
    db.Products.Add(product);
    await db.SaveChangesAsync();
    return Results.Created($"/products/{product.Id}", product);
});

app.MapDelete("/products/{id}", async (ShopContext db, string id) =>
{
    if (await db.Products.FindAsync(id) is Product p)
    {
        db.Products.Remove(p);
        await db.SaveChangesAsync();
        return Results.NoContent();
    }
    return Results.NotFound();
});

app.Run();

Property Mapping

The EF Core provider automatically maps C# PascalCase property names to OxiDB's snake_case field names:

C# PropertyOxiDB Field
FirstNamefirst_name
CreatedAtcreated_at
ProductIdproduct_id
Id_key (primary key)

Entity types map to collections by their short name in lowercase. DbSet<Product> maps to collection "product", DbSet<Order> maps to "order".

Architecture

┌─────────────────────────────────────────────┐
│              Your Application                │
│                                              │
│   DbContext  ←→  LINQ  ←→  Change Tracker   │
└──────────────────┬──────────────────────────┘
                   │
         OxiDb.EntityFrameworkCore
         (query translation, DI, mapping)
                   │
          ┌────────┴────────┐
          │  IOxiDbClient   │
          └────────┬────────┘
           ┌───────┴───────┐
           │               │
    OxiDb.Client.Tcp  OxiDb.Client.Embedded
    (network client)  (in-process FFI)
           │               │
    ┌──────┴──────┐  ┌─────┴─────┐
    │ OxiDB Server│  │Native Rust│
    │   (TCP)     │  │  Library  │
    └─────────────┘  └───────────┘

Download

OxiDb.Client.Tcp (16 KB) OxiDb.Client.Embedded (2.3 MB) OxiDb.EntityFrameworkCore (23 KB)

# Install via dotnet CLI
dotnet add package OxiDb.Client.Tcp --version 0.18.1
dotnet add package OxiDb.Client.Embedded --version 0.18.1
dotnet add package OxiDb.EntityFrameworkCore --version 0.18.1

All packages target .NET 10.0. The TCP client has zero dependencies. The embedded client includes native runtimes for macOS, Linux, and Windows. The EF Core provider depends on Microsoft.EntityFrameworkCore 10.0.