Skip to content

Platform · Files

The database as a file

IBsqliteStorageAdmin treats a database as an artifact rather than a connection: what exists, read the bytes out, write bytes back, delete. Cross-provider migration and the diagnostics on Storage are built from this same surface, and none of it goes through EF.

Client database OPFS

Fastest persistent tier. Real files in the origin private file system. Concurrent connections, no COOP/COEP.

List

What each backend holds

Names come from the provider, so a backend that has never been used reports empty rather than failing. Related -journal files are not databases and do not appear.

Live
csharp Listing databases
// Databases as files, outside any SQL connection. No EF involved.
foreach (var provider in Database.Providers)
{
    IReadOnlyList<string> names = await provider.Admin.ListAsync();
}
Export

Download a real .db

Exports app.db from whichever backend currently owns it. On OPFS that is a file read; on IndexedDB and Cache Storage the image is assembled from pages. Either way the result is an ordinary SQLite file.

Try Download it and open it in any desktop SQLite tool - the rows you edited are there.
Live
csharp Exporting
var session = await Database.EnsureSessionAsync();
var provider = session.Resolution.Provider;

byte[] image = await provider.Admin.ExportAsync("app.db");

// A plain SQLite file: open it in any desktop tool.
await js.InvokeVoidAsync("bsqliteDemo.download", "app.db", image);
Import

Seed a tab from a file

Replaces the named database on the selected backend and records the sticky binding, so the next open finds the imported data instead of creating an empty file elsewhere. The worker is closed first: an open connection would keep writing the image being replaced.

Try Export above, delete below, then import the file back. This is also how you ship a pre-built database with an app.
Live
csharp Importing
// Close the worker first so it cannot keep writing the image being replaced.
await Database.CloseSessionAsync();

await provider.Admin.ImportAsync("app.db", bytes);

// Record the sticky binding, or the next open would create an empty file on the
// preferred backend and the import would look like it vanished.
await Database.Bindings.SetProviderNameAsync("app.db", provider.Name);

// Reopen once so migrations run before the pages come back for the database. The
// open raises Opened, which is how every page hears it should reload.
await using (await Database.OpenContextAsync())
{
}
Delete

Start over

Removes app.db from the current backend and forgets the binding, so the next open is free to pick the preferred provider again, run the migrations, and reseed.

Live
csharp Deleting
await Database.CloseSessionAsync();
await provider.Admin.DeleteAsync("app.db");

// Forget the binding so selection is free to pick the preferred backend again.
await Database.Bindings.RemoveAsync("app.db");

// Migrates and reseeds the now-empty database.
await using (await Database.OpenContextAsync())
{
}
An unhandled error has occurred. Reload 🗙