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:
[[Svg Src="./witdatabase-deployment-comparison.svg" Alt="witdatabase-deployment-comparison"]]
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
[[Svg Src="./witdatabase-blazor-architecture.svg" Alt="witdatabase-blazor-architecture"]]
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 layer
Example: 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 =
Loading...
quot;{_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 =
Loading...
quot;{_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 =
Loading...
quot;{_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
[[Svg Src="./witdatabase-encryption-algorithm-decision.svg" Alt="witdatabase-encryption-algorithm-decision"]]
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