WitDatabase is a pure .NET library with no native dependencies, enabling it to run on any platform that supports .NET. This includes desktop, server, mobile, and even web browsers via Blazor WebAssembly.
1. Overview
Supported Platforms
WitDatabase runs everywhere .NET runs:
| Platform | Support | Storage Backend | Notes |
|---|---|---|---|
| Windows (x64, x86, ARM64) | ✅ Full | File | All features |
| Linux (x64, ARM64) | ✅ Full | File | All features |
| macOS (x64, Apple Silicon) | ✅ Full | File | All features |
| Blazor WebAssembly | ✅ Full | IndexedDB | Browser-based |
| iOS (via MAUI) | ✅ Full | File | Mobile |
| Android (via MAUI) | ✅ Full | File | Mobile |
.NET Version Requirements
| .NET Version | Support | Notes |
|---|---|---|
| .NET 10.0 | ✅ Full | Recommended |
| .NET 9.0 | ✅ Full | Fully supported |
| .NET 8.0 | ⚠️ Untested | May work |
| .NET Framework | ❌ No | Not supported |
Why Pure .NET Matters
Unlike SQLite which requires platform-specific native binaries, WitDatabase is 100% managed code:
Platform-Specific Considerations
| Platform | Encryption | Storage Engine | Special Package |
|---|---|---|---|
| Windows/Linux/macOS | AES-GCM (fast) | B+Tree, LSM-Tree | None |
| Blazor WebAssembly | ChaCha20 (recommended) | B+Tree only | OutWit.Database.Core.IndexedDb |
| iOS/Android | AES-GCM or ChaCha20 | B+Tree, LSM-Tree | None |
| ARM without AES-NI | ChaCha20 (recommended) | B+Tree, LSM-Tree | OutWit.Database.Core.BouncyCastle |
Quick Start by Platform
Desktop/Server (Windows, Linux, macOS):
var db = new WitDatabaseBuilder()
.WithFilePath("app.witdb")
.WithBTree()
.WithTransactions()
.Build();Blazor WebAssembly:
var db = new WitDatabaseBuilder()
.WithIndexedDbStorage("MyApp", JSRuntime)
.WithBTree()
.WithBouncyCastleEncryption("password") // ChaCha20 for WASM
.Build();
await db.InitializeAsync();Mobile (MAUI):
var dbPath = Path.Combine(FileSystem.AppDataDirectory, "app.witdb");
var db = new WitDatabaseBuilder()
.WithFilePath(dbPath)
.WithBTree()
.WithEncryption("password")
.Build();2. Desktop and Server
Windows
WitDatabase runs on all Windows versions that support .NET 9+:
| Windows Version | x64 | x86 | ARM64 |
|---|---|---|---|
| Windows 11 | ✅ | ✅ | ✅ |
| Windows 10 | ✅ | ✅ | ✅ |
| Windows Server 2022 | ✅ | — | ✅ |
| Windows Server 2019 | ✅ | — | — |
Recommended configuration:
// Windows desktop app
var dbPath = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
"MyApp",
"data.witdb"
);
var db = new WitDatabaseBuilder()
.WithFilePath(dbPath)
.WithBTree()
.WithEncryption("password") // AES-GCM, hardware accelerated
.WithTransactions()
.Build();Windows-specific features:
- AES-NI hardware acceleration (most modern CPUs)
- NTFS file locking for multi-process safety
- Full async I/O support
Linux
WitDatabase supports major Linux distributions:
| Distribution | x64 | ARM64 |
|---|---|---|
| Ubuntu 20.04+ | ✅ | ✅ |
| Debian 11+ | ✅ | ✅ |
| Fedora 38+ | ✅ | ✅ |
| Alpine 3.17+ | ✅ | ✅ |
| RHEL/CentOS 8+ | ✅ | ✅ |
Recommended configuration:
// Linux server
var dbPath = "/var/lib/myapp/data.witdb";
var db = new WitDatabaseBuilder()
.WithFilePath(dbPath)
.WithBTree()
.WithEncryption("password") // AES-GCM on x64
.WithTransactions()
.Build();Linux-specific considerations:
- File permissions: Ensure app has read/write access to database directory
- Docker: Mount a volume for data persistence
- ARM64 (Raspberry Pi, etc.): Consider ChaCha20 if no AES-NI
Docker example:
FROM mcr.microsoft.com/dotnet/aspnet:9.0
WORKDIR /app
COPY --from=build /app/publish .
# Create data directory
RUN mkdir -p /data && chown -R app:app /data
VOLUME /data
ENV DB_PATH=/data/app.witdb
ENTRYPOINT ["dotnet", "MyApp.dll"]// In app
var dbPath = Environment.GetEnvironmentVariable("DB_PATH") ?? "/data/app.witdb";macOS
WitDatabase supports both Intel and Apple Silicon Macs:
| macOS Version | Intel (x64) | Apple Silicon (ARM64) |
|---|---|---|
| macOS 14+ (Sonoma) | ✅ | ✅ |
| macOS 13 (Ventura) | ✅ | ✅ |
| macOS 12 (Monterey) | ✅ | ✅ |
Recommended configuration:
// macOS app
var dbPath = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
"MyApp",
"data.witdb"
);
var db = new WitDatabaseBuilder()
.WithFilePath(dbPath)
.WithBTree()
.WithEncryption("password") // AES-GCM on both Intel and M-series
.WithTransactions()
.Build();macOS-specific features:
- AES hardware acceleration on both Intel and Apple Silicon
- App Sandbox compatible (use app container for data)
- Notarization compatible (no native code to sign)
Server Deployment Best Practices
Connection string for production:
"Data Source=/var/lib/myapp/prod.witdb;Encryption=aes-gcm;Password=<from-secrets>;Cache Size=10000;MVCC=true;Isolation Level=Snapshot"ASP.NET Core configuration:
// Program.cs
builder.Services.AddDbContext<AppDbContext>(options =>
{
var connStr = builder.Configuration.GetConnectionString("WitDb");
options.UseWitDb(connStr);
});
// appsettings.json
{
"ConnectionStrings": {
"WitDb": "Data Source=/data/app.witdb;Encryption=aes-gcm;Password=${DB_PASSWORD}"
}
}3. Blazor WebAssembly
WitDatabase can run entirely in the browser using IndexedDB as the storage backend. This enables offline-first web applications with local data persistence.
How It Works
Installation
Install the required packages:
<PackageReference Include="OutWit.Database.Core.IndexedDb" Version="1.0.0" />
<PackageReference Include="OutWit.Database.Core.BouncyCastle" Version="1.0.0" />Add JavaScript files to wwwroot/index.html:
<script src="_content/OutWit.Database.Core.IndexedDb/witdb-indexeddb.js"></script>
<script src="_content/OutWit.Database.Core.IndexedDb/witdb-indexeddb-index.js"></script>Basic Usage
@page "/data"
@inject IJSRuntime JSRuntime
@using OutWit.Database.Core.Builder
@using OutWit.Database.Core.IndexedDb
@using OutWit.Database.Core.BouncyCastle
@code {
private WitDatabase? _db;
protected override async Task OnInitializedAsync()
{
_db = new WitDatabaseBuilder()
.WithIndexedDbStorage("MyAppDatabase", JSRuntime)
.WithBTree()
.WithTransactions()
.Build();
// Must initialize async in WASM
await ((StorageIndexedDb)_db.Store).InitializeAsync();
}
private async Task SaveData(string key, byte[] value)
{
await _db!.PutAsync(Encoding.UTF8.GetBytes(key), value);
}
private async Task<byte[]?> LoadData(string key)
{
return await _db!.GetAsync(Encoding.UTF8.GetBytes(key));
}
public async ValueTask DisposeAsync()
{
if (_db != null)
{
await _db.FlushAsync();
_db.Dispose();
}
}
}With Encryption
Use ChaCha20-Poly1305 for better WASM performance (no AES-NI in browser):
_db = new WitDatabaseBuilder()
.WithIndexedDbStorage("SecureApp", JSRuntime)
.WithBTree()
.WithBouncyCastleEncryptionFast("user", userPassword) // ChaCha20, fast mode
.WithTransactions()
.Build();Database Service Pattern
Create a reusable service for database access:
// Services/DatabaseService.cs
public class DatabaseService : IAsyncDisposable
{
private readonly IJSRuntime _jsRuntime;
private WitDatabase? _db;
public DatabaseService(IJSRuntime jsRuntime)
{
_jsRuntime = jsRuntime;
}
public async Task InitializeAsync(string? password = null)
{
var builder = new WitDatabaseBuilder()
.WithIndexedDbStorage("MyApp", _jsRuntime)
.WithBTree()
.WithTransactions();
if (!string.IsNullOrEmpty(password))
{
builder.WithBouncyCastleEncryption(password);
}
_db = builder.Build();
await ((StorageIndexedDb)_db.Store).InitializeAsync();
}
public WitDatabase Database => _db
?? throw new InvalidOperationException("Database not initialized");
public async ValueTask DisposeAsync()
{
if (_db != null)
{
await _db.FlushAsync();
_db.Dispose();
}
}
}
// Register in Program.cs
builder.Services.AddScoped<DatabaseService>();Browser Compatibility
| Browser | Minimum Version | IndexedDB Support |
|---|---|---|
| Chrome | 80+ | ✅ Full |
| Edge | 80+ | ✅ Full |
| Firefox | 75+ | ✅ Full |
| Safari | 14+ | ✅ Full |
WASM Limitations
| Feature | Desktop/Server | Blazor WASM |
|---|---|---|
| B+Tree engine | ✅ | ✅ |
| LSM-Tree engine | ✅ | ❌ (requires file system) |
| AES-GCM encryption | ✅ Fast | ⚠️ Slow (no AES-NI) |
| ChaCha20 encryption | ✅ | ✅ Fast |
| Transactions | ✅ | ✅ |
| MVCC | ✅ | ✅ |
| Secondary indexes | ✅ | ✅ |
| SQL Engine | ✅ | ✅ |
| Sync I/O | ✅ | ❌ (must use async) |
Storage Limits
IndexedDB storage limits vary by browser:
| Browser | Storage Limit |
|---|---|
| Chrome | 60% of disk space (or ~2GB minimum) |
| Firefox | 50% of disk space |
| Safari | 1GB (may prompt for more) |
| Edge | Same as Chrome |
Best practices for WASM:
- Use ChaCha20 encryption (faster than AES in WASM)
- Use fast PBKDF2 mode for quicker startup
- Keep cache size small (300-500 pages)
- Always use async APIs
4. Mobile (MAUI)
WitDatabase works with .NET MAUI for iOS and Android applications. It uses standard file storage on mobile devices.
Platform Support
| Platform | Support | Storage Location |
|---|---|---|
| iOS (iPhone, iPad) | ✅ Full | App Documents folder |
| Android | ✅ Full | App internal storage |
| Windows (via MAUI) | ✅ Full | LocalApplicationData |
| macOS (via MAUI) | ✅ Full | App container |
Installation
<PackageReference Include="OutWit.Database.Core" Version="1.0.0" />
<!-- Or for SQL support -->
<PackageReference Include="OutWit.Database.AdoNet" Version="1.0.0" />
<!-- For ChaCha20 on older ARM devices -->
<PackageReference Include="OutWit.Database.Core.BouncyCastle" Version="1.0.0" />Basic Usage
// MauiProgram.cs
public static class MauiProgram
{
public static MauiApp CreateMauiApp()
{
var builder = MauiApp.CreateBuilder();
builder
.UseMauiApp<App>()
.ConfigureFonts(fonts =>
{
fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
});
// Register database service
builder.Services.AddSingleton<IDatabaseService, DatabaseService>();
return builder.Build();
}
}// Services/DatabaseService.cs
public interface IDatabaseService
{
WitDatabase Database { get; }
Task InitializeAsync();
}
public class DatabaseService : IDatabaseService, IDisposable
{
private WitDatabase? _db;
public WitDatabase Database => _db
?? throw new InvalidOperationException("Database not initialized");
public Task InitializeAsync()
{
var dbPath = Path.Combine(
FileSystem.AppDataDirectory, // Platform-appropriate location
"app.witdb"
);
_db = new WitDatabaseBuilder()
.WithFilePath(dbPath)
.WithBTree()
.WithEncryption("your-secure-password")
.WithTransactions()
.Build();
return Task.CompletedTask;
}
public void Dispose()
{
_db?.Dispose();
}
}Platform-Specific Paths
// FileSystem.AppDataDirectory resolves to:
// iOS: /var/mobile/Containers/Data/Application/{GUID}/Library/
// Android: /data/data/{package-name}/files/
// Windows: C:\Users\{user}\AppData\Local\{app}\
// macOS: /Users/{user}/Library/Containers/{bundle-id}/Data/Library/Encryption on Mobile
iOS and modern Android have hardware AES support:
// AES-GCM (hardware accelerated on modern devices)
var db = new WitDatabaseBuilder()
.WithFilePath(dbPath)
.WithBTree()
.WithEncryption("password") // AES-GCM
.Build();Older ARM devices without AES-NI:
// ChaCha20 (faster on older ARM)
var db = new WitDatabaseBuilder()
.WithFilePath(dbPath)
.WithBTree()
.WithBouncyCastleEncryption("password") // ChaCha20
.Build();Mobile Best Practices
1. Initialize on app start:
// App.xaml.cs
public partial class App : Application
{
private readonly IDatabaseService _dbService;
public App(IDatabaseService dbService)
{
InitializeComponent();
_dbService = dbService;
MainPage = new AppShell();
}
protected override async void OnStart()
{
await _dbService.InitializeAsync();
}
}2. Handle app lifecycle:
// Flush on background/suspend
protected override void OnSleep()
{
_dbService.Database.Flush();
}3. Use reasonable cache size:
// Mobile devices have limited memory
var db = new WitDatabaseBuilder()
.WithFilePath(dbPath)
.WithBTree()
.WithCache(cacheSize: 500) // Conservative for mobile
.Build();4. Consider SQLite data protection (iOS):
// iOS Data Protection is automatic for app container files
// WitDatabase encryption adds additional layerExample: Offline-First Mobile App
public class OfflineRepository<T> where T : class, IEntity
{
private readonly WitDatabase _db;
private readonly string _tableName;
public OfflineRepository(WitDatabase db, string tableName)
{
_db = db;
_tableName = tableName;
}
public async Task SaveAsync(T entity)
{
var key = $"{_tableName}:{entity.Id}";
var value = JsonSerializer.SerializeToUtf8Bytes(entity);
await _db.PutAsync(Encoding.UTF8.GetBytes(key), value);
}
public async Task<T?> GetAsync(string id)
{
var key = $"{_tableName}:{id}";
var value = await _db.GetAsync(Encoding.UTF8.GetBytes(key));
return value != null
? JsonSerializer.Deserialize<T>(value)
: null;
}
public async Task DeleteAsync(string id)
{
var key = $"{_tableName}:{id}";
await _db.DeleteAsync(Encoding.UTF8.GetBytes(key));
}
}5. Encryption by Platform
Different platforms have different capabilities for hardware-accelerated encryption. Choosing the right algorithm ensures optimal performance.
Algorithm Selection Guide
Platform Recommendations
| Platform | Recommended Algorithm | Reason |
|---|---|---|
| Windows (x64) | AES-GCM | AES-NI hardware acceleration |
| Windows (ARM64) | AES-GCM | ARMv8 crypto extensions |
| Linux (x64) | AES-GCM | AES-NI hardware acceleration |
| Linux (ARM64) | AES-GCM | ARMv8 crypto extensions |
| macOS (Intel) | AES-GCM | AES-NI hardware acceleration |
| macOS (Apple Silicon) | AES-GCM | Hardware acceleration |
| iOS (iPhone 5s+) | AES-GCM | ARMv8 crypto extensions |
| Android (2015+) | AES-GCM | ARMv8 crypto extensions |
| Older Android | ChaCha20 | No AES hardware |
| Blazor WASM | ChaCha20 | No hardware acceleration |
| Raspberry Pi 4 | AES-GCM | ARMv8 crypto extensions |
| Raspberry Pi 3 | ChaCha20 | No AES hardware |
Performance Comparison
Encrypting 1000 4KB pages:
| Platform | AES-GCM | ChaCha20 |
|---|---|---|
| Intel i7 (AES-NI) | 15 ms | 45 ms |
| AMD Ryzen (AES-NI) | 12 ms | 40 ms |
| Apple M1 | 10 ms | 35 ms |
| iPhone 14 | 18 ms | 50 ms |
| Android (Snapdragon 8) | 20 ms | 55 ms |
| Raspberry Pi 4 | 80 ms | 100 ms |
| ARM without AES | 120 ms | 60 ms |
| Blazor WASM | 800 ms | 200 ms |
Configuration Examples
Desktop/Server (AES-GCM):
// Built-in, no extra package needed
var db = new WitDatabaseBuilder()
.WithFilePath("secure.witdb")
.WithEncryption("password") // AES-GCM
.Build();Blazor WASM (ChaCha20):
// Requires OutWit.Database.Core.BouncyCastle
var db = new WitDatabaseBuilder()
.WithIndexedDbStorage("SecureApp", JSRuntime)
.WithBouncyCastleEncryptionFast("user", "password") // ChaCha20, fast PBKDF2
.Build();Cross-platform with runtime detection:
public WitDatabaseBuilder ConfigureEncryption(WitDatabaseBuilder builder, string password)
{
// Detect if we should use ChaCha20
bool useChaCha20 =
OperatingSystem.IsBrowser() || // Blazor WASM
(OperatingSystem.IsAndroid() && !HasAesNi()); // Older Android
if (useChaCha20)
{
return builder.WithBouncyCastleEncryption(password);
}
else
{
return builder.WithEncryption(password);
}
}
private bool HasAesNi()
{
// On Android, check CPU features
// Most devices from 2015+ have ARMv8 crypto
return true; // Simplified; implement actual detection if needed
}Key Derivation Performance
PBKDF2 iteration count affects startup time:
| Mode | Iterations | Desktop | Mobile | WASM |
|---|---|---|---|---|
| Normal | 100,000 | 50 ms | 150 ms | 2+ sec |
| Fast | 10,000 | 5 ms | 15 ms | 200 ms |
Use fast mode for WASM:
// Blazor WASM — fast PBKDF2
builder.WithBouncyCastleEncryptionFast("user", "password");
// Or via connection string
"Encryption=chacha20-poly1305;Password=secret;Fast Encryption=true"6. Quick Reference
Platform Compatibility Matrix
| Feature | Windows | Linux | macOS | iOS | Android | WASM |
|---|---|---|---|---|---|---|
| B+Tree | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| LSM-Tree | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ |
| AES-GCM | ✅ Fast | ✅ Fast | ✅ Fast | ✅ Fast | ✅ Fast | ⚠️ Slow |
| ChaCha20 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ Fast |
| Transactions | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| MVCC | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| WAL | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ |
| SQL Engine | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| ADO.NET | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| EF Core | ✅ | ✅ | ✅ | ✅ | ✅ | ⚠️ Limited |
| Secondary Indexes | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
Required Packages by Platform
| Platform | Core | IndexedDB | BouncyCastle | AdoNet | EF Core |
|---|---|---|---|---|---|
| Desktop/Server | ✅ Required | — | Optional | Optional | Optional |
| Blazor WASM | ✅ Required | ✅ Required | ✅ Recommended | Optional | ⚠️ Limited |
| iOS/Android | ✅ Required | — | Optional | Optional | Optional |
Configuration by Platform
Windows/Linux/macOS:
"Data Source=/path/to/app.witdb;Encryption=aes-gcm;Password=secret"Blazor WASM:
var db = new WitDatabaseBuilder()
.WithIndexedDbStorage("AppName", JSRuntime)
.WithBouncyCastleEncryptionFast("user", "password")
.WithBTree()
.Build();
await db.InitializeAsync();MAUI (iOS/Android):
var path = Path.Combine(FileSystem.AppDataDirectory, "app.witdb");
"Data Source=" + path + ";Encryption=aes-gcm;Password=secret"Storage Locations
| Platform | Recommended Path |
|---|---|
| Windows | Environment.SpecialFolder.LocalApplicationData |
| Linux | /var/lib/{appname}/ or ~/.local/share/{appname}/ |
| macOS | Environment.SpecialFolder.LocalApplicationData |
| iOS | FileSystem.AppDataDirectory |
| Android | FileSystem.AppDataDirectory |
| WASM | IndexedDB (automatic) |
Performance Tips by Platform
Desktop/Server:
- Use large cache (5000-20000 pages)
- Enable MVCC for concurrent access
- Use LSM-Tree for write-heavy workloads
Mobile:
- Use moderate cache (500-1000 pages)
- Flush on app suspend
- Consider ChaCha20 on older devices
Blazor WASM:
- Use small cache (300-500 pages)
- Use ChaCha20 with fast PBKDF2
- Always use async APIs
- B+Tree only (no LSM-Tree)
Troubleshooting
| Issue | Platform | Solution |
|---|---|---|
| Slow encryption | WASM | Switch to ChaCha20 |
| Slow startup | WASM | Use fast PBKDF2 mode |
| Storage full | WASM | Check IndexedDB quota |
| File access denied | Mobile | Check app permissions |
| Database locked | All | Check file locking settings |
| Sync I/O hangs | WASM | Use async APIs only |