OutWit.Database.Core.IndexedDb
13.1.1
dotnet add package OutWit.Database.Core.IndexedDb --version 13.1.1
NuGet\Install-Package OutWit.Database.Core.IndexedDb -Version 13.1.1
<PackageReference Include="OutWit.Database.Core.IndexedDb" Version="13.1.1" />
<PackageVersion Include="OutWit.Database.Core.IndexedDb" Version="13.1.1" />
<PackageReference Include="OutWit.Database.Core.IndexedDb" />
paket add OutWit.Database.Core.IndexedDb --version 13.1.1
#r "nuget: OutWit.Database.Core.IndexedDb, 13.1.1"
#:package OutWit.Database.Core.IndexedDb@13.1.1
#addin nuget:?package=OutWit.Database.Core.IndexedDb&version=13.1.1
#tool nuget:?package=OutWit.Database.Core.IndexedDb&version=13.1.1
OutWit.Database.Core.IndexedDb
IndexedDB storage provider for WitDatabase - enables Blazor WebAssembly support.
This package allows WitDatabase to run entirely in the browser with data persisted to IndexedDB.
Use 12.8.0 or later. Everything below is written around the asynchronous API, because in a browser there is no other kind - and from 12.0.0 to 12.7.0 that API did not reach storage.
BTreeConcurrentStore, which wraps every B+Tree store, implemented each async method by calling the synchronous one, so a database built on this provider could be created and never written to. Fixed in 12.8.0 with a lock that survives a continuation resuming on another thread.
Installation
<PackageReference Include="OutWit.Database.Core.IndexedDb" Version="12.8.0" />
Add the JavaScript files to your 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>
Quick Start
Basic Usage
@page "/database-demo"
@inject IJSRuntime JSRuntime
@using OutWit.Database.Core.Builder
@using OutWit.Database.Core.IndexedDb
<h3>Database Demo</h3>
@code {
private WitDatabase? _db;
protected override async Task OnInitializedAsync()
{
_db = new WitDatabaseBuilder()
.WithIndexedDbStorage("MyAppDatabase", JSRuntime)
.WithBTree()
.WithTransactions()
.Build();
// Initialize storage (opens IndexedDB)
await (_db.Store as StorageIndexedDb)?.InitializeAsync()!;
}
private async Task SaveData()
{
var key = Encoding.UTF8.GetBytes("user:1");
var value = Encoding.UTF8.GetBytes("{\"name\":\"John\"}");
await _db!.PutAsync(key, value);
}
private async Task LoadData()
{
var key = Encoding.UTF8.GetBytes("user:1");
var value = await _db!.GetAsync(key);
if (value != null)
{
var json = Encoding.UTF8.GetString(value);
Console.WriteLine(json);
}
}
public async ValueTask DisposeAsync()
{
if (_db != null)
{
await _db.DisposeAsync();
}
}
}
With Encryption
var db = new WitDatabaseBuilder()
.WithIndexedDbStorage("SecureDatabase", JSRuntime)
.WithBTree()
.WithEncryption("user-password") // AES-GCM encryption
.WithTransactions()
.Build();
With MVCC
var db = new WitDatabaseBuilder()
.WithIndexedDbStorage("MvccDatabase", JSRuntime)
.WithBTree()
.WithMvcc()
.WithDefaultIsolationLevel(IsolationLevel.Snapshot)
.Build();
Compatibility
Storage Engines
| Engine | Compatible | Notes |
|---|---|---|
| B+Tree (WithBTree) | Yes | Recommended, full support |
| LSM-Tree (WithLsmTree) | No | Requires file system |
| In-Memory | Yes | No persistence |
Features
| Feature | Compatible | Notes |
|---|---|---|
| Basic CRUD | Yes | Full support |
| Transactions | Yes | Via TransactionalStore |
| MVCC | Yes | All isolation levels |
| Savepoints | Yes | Full support |
| Encryption | Yes | AES-GCM, BouncyCastle |
| Secondary Indexes | Yes | Full support via IndexedDB |
| File Locking | No | Not applicable |
| WAL/Journal | No | Single-file model |
Browsers
| Browser | Supported |
|---|---|
| Chrome 80+ | Yes |
| Firefox 75+ | Yes |
| Edge 80+ | Yes |
| Safari 14+ | Yes |
Secondary Indexes
Secondary indexes are automatically configured when using WithIndexedDbStorage(). Each index uses a separate object store within a dedicated IndexedDB database.
Automatic Configuration
// Indexes are automatically configured
var db = new WitDatabaseBuilder()
.WithIndexedDbStorage("MyDatabase", JSRuntime)
.WithBTree()
.Build();
// Index factory is automatically set up for IndexedDB
// Indexes will use "MyDatabase_indexes" database
Custom Index Database
var db = new WitDatabaseBuilder()
.WithIndexedDbStorage("MyDatabase", JSRuntime)
.WithIndexedDbIndexes(JSRuntime, "CustomIndexDb") // Override default
.WithBTree()
.Build();
Using Indexes
// Create index manager
var indexFactory = new SecondaryIndexFactoryIndexedDb(JSRuntime, "MyDatabase_indexes");
var indexManager = new IndexManager(indexFactory);
// Create a secondary index
var emailIndex = indexManager.CreateIndex("idx_email", isUnique: true);
// Add entries
emailIndex.Add(emailBytes, primaryKeyBytes);
// Find by index
var primaryKeys = emailIndex.Find(emailBytes);
API Reference
WitDatabaseBuilder Extensions
// Basic IndexedDB storage (auto-configures indexes)
builder.WithIndexedDbStorage(string databaseName, IJSRuntime jsRuntime)
// With custom page size
builder.WithIndexedDbStorage(string databaseName, IJSRuntime jsRuntime, int pageSize)
// Custom index database
builder.WithIndexedDbIndexes(IJSRuntime jsRuntime, string indexDatabaseName)
StorageIndexedDb
// Create storage directly
var storage = new StorageIndexedDb("DatabaseName", jsRuntime);
// Async initialization (recommended)
await storage.InitializeAsync();
// Check if database exists
bool exists = await storage.DatabaseExistsAsync();
// Properties
storage.DatabaseName // IndexedDB database name
storage.PageSize // Page size in bytes
storage.PageCount // Total number of pages
storage.IsInitialized // Whether storage is initialized
SecondaryIndexFactoryIndexedDb
// Create index factory
var factory = new SecondaryIndexFactoryIndexedDb(jsRuntime, "DatabaseName");
// Create indexes
var uniqueIndex = factory.CreateIndex("idx_unique", isUnique: true);
var nonUniqueIndex = factory.CreateIndex("idx_category", isUnique: false);
// Factory properties
factory.ProviderKey // "indexeddb"
IndexedDbInterop
Low-level IndexedDB operations (advanced usage):
var interop = new IndexedDbInterop(jsRuntime, "DatabaseName");
await interop.OpenAsync();
await interop.WritePageAsync(0, pageData);
var data = await interop.ReadPageAsync(0);
await interop.CloseAsync();
Limitations
No LSM-Tree Support
- LSM-Tree requires file system operations
- Use B+Tree instead
Single-Tab Access
- IndexedDB can be accessed from multiple tabs
- But WitDatabase does not coordinate between tabs
- Use single-tab or implement your own coordination
Storage Quota
- Browser limits IndexedDB storage (typically 50-100MB minimum)
- Check available quota with
navigator.storage.estimate()
Sync Operations
- Sync methods use async bridge internally
- Prefer async methods for better performance
Error Handling
Configuration Errors
try
{
var db = new WitDatabaseBuilder()
.WithIndexedDbStorage("MyDatabase", JSRuntime)
.WithLsmTree() // ERROR!
.Build();
}
catch (InvalidOperationException ex)
{
// "IndexedDB storage is not compatible with LSM-Tree engine..."
}
Page Size Mismatch
try
{
// First open with 4096
var db1 = new WitDatabaseBuilder()
.WithIndexedDbStorage("MyDatabase", JSRuntime, pageSize: 4096)
.Build();
db1.Dispose();
// Try to open with different page size
var db2 = new WitDatabaseBuilder()
.WithIndexedDbStorage("MyDatabase", JSRuntime, pageSize: 8192) // ERROR!
.Build();
}
catch (InvalidOperationException ex)
{
// "Database was created with page size 4096, but 8192 was requested..."
}
Troubleshooting
JavaScript Not Loaded
If you see errors about witDb or witDbIndex being undefined:
- Ensure both script tags are in
index.html - Make sure they are loaded before your Blazor app starts
- Check browser console for script loading errors
IndexedDB Not Available
// Check if IndexedDB is available
if (window.indexedDB == null)
{
// IndexedDB not supported or blocked
}
Quota Exceeded
try
{
await db.PutAsync(key, largeValue);
}
catch (JSException ex) when (ex.Message.Contains("quota"))
{
// Storage quota exceeded
// Consider cleanup or ask user to allow more storage
}
Performance Tips
Use Async Methods
// Preferred await db.PutAsync(key, value); // Avoid when possible (uses sync bridge) db.Put(key, value);Batch Operations
using var tx = db.BeginTransaction(); foreach (var item in items) { tx.Put(item.Key, item.Value); } tx.Commit();Appropriate Page Size
- Default 4096 is good for small records
- Use 8192-16384 for larger records
See Also
- OutWit.Database.Core - Core database library
- OutWit.Database.Core.BouncyCastle - ChaCha20 encryption
- MDN: IndexedDB
- Blazor JS Interop
- ROADMAP.md - Planned features
License
Licensed under the Apache License, Version 2.0. See LICENSE.
Attribution (optional)
If you use OutWit.Database.Core.IndexedDb in a product, a mention is appreciated (but not required), for example: "Powered by WitDatabase https://witdatabase.io/".
Trademark / Project name
"WitDatabase" and the WitDatabase logo are used to identify the official project by Dmitry Ratner.
You may:
- refer to the project name in a factual way (e.g., "built with WitDatabase");
- use the name to indicate compatibility (e.g., "WitDatabase-compatible").
You may not:
- use "WitDatabase" as the name of a fork or a derived product in a way that implies it is the official project;
- use the WitDatabase logo to promote forks or derived products without permission.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. 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. |
-
net10.0
- Microsoft.JSInterop (>= 10.0.10)
- OutWit.Database.Core (>= 13.1.1)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 13.1.1 | 0 | 8/15/2026 |
| 13.1.0 | 32 | 8/14/2026 |
| 12.8.0 | 72 | 8/11/2026 |
| 12.7.0 | 87 | 8/10/2026 |
| 12.6.0 | 84 | 8/10/2026 |
| 12.5.0 | 79 | 8/10/2026 |
| 12.4.0 | 79 | 8/9/2026 |
| 12.3.0 | 78 | 8/9/2026 |
| 12.2.1 | 80 | 8/9/2026 |
| 12.2.0 | 98 | 8/4/2026 |
| 12.1.0 | 105 | 8/4/2026 |
| 12.0.0 | 99 | 8/3/2026 |
| 11.2.0 | 91 | 8/3/2026 |
| 11.1.0 | 94 | 8/3/2026 |
| 11.0.0 | 103 | 8/2/2026 |
| 10.0.0 | 97 | 8/1/2026 |
| 9.0.0 | 105 | 8/1/2026 |
| 8.0.0 | 99 | 7/31/2026 |
| 7.0.0 | 103 | 7/31/2026 |
| 6.0.0 | 91 | 7/30/2026 |