Skip to content

Platform · Honesty

What the browser cannot do

The default tier is asynchronous: the engine lives in a worker and the Blazor UI thread is not allowed to block on it. Some SQLite features cannot be honoured on the web at all. Each one below fails with a typed exception that names the alternative, rather than half-working - run them and read the real message.

Client database OPFS

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

Synchronous EF and ADO.NET

SaveChanges(), ToList(), and DbConnection.Open() throw BsqliteSynchronousApiNotSupportedException, and the message names the async overload to use. The opt-in tier that would lift this (COOP/COEP plus a native ISQLite3Provider) slipped past 1.0. EF wraps a failed save, so the panel below unwraps to the exception that actually explains the refusal.

Try Run it: this is the exception your users would see, not a paraphrase of it.
Live
csharp Calling SaveChanges()
await using var context = await Database.OpenContextAsync();

// EF short-circuits SaveChanges() when nothing is pending, so stage a real insert
// first - otherwise the call returns 0 and never reaches the connection.
context.Categories.Add(new Category { Name = "sync-probe", Color = "#0f766e" });

context.SaveChanges();
// DbUpdateException -> BsqliteSynchronousApiNotSupportedException:
//   the engine is in a worker and the Blazor UI thread cannot block on it.
//   Use SaveChangesAsync(). Same for ToList(), First(), DbConnection.Open().
//
// EF wraps save failures, so read InnerException for the message that explains it.

WAL journal mode

No web VFS implements WAL: WASM lacks the shared-memory primitives it needs, and the official SQLite WASM build cannot even read a WAL-mode file. Journal mode here is DELETE or TRUNCATE. Concurrent reads, where a backend offers them, come from the VFS instead.

Live
csharp PRAGMA journal_mode=WAL
await Database.ExecuteNonQueryAsync("PRAGMA journal_mode=WAL");
// No web VFS implements WAL: WASM has no shared-memory primitives for it, and the
// official SQLite WASM build cannot even read a WAL-mode file.
// Journal mode is DELETE or TRUNCATE. Concurrent reads are a VFS capability instead:
//   session.Resolution.Provider.Capabilities.SupportsConcurrentReads

ATTACH across two databases

Gated by SupportsMultiDatabaseTransactions: OPFS CoopSync cannot run a transaction spanning two files, IndexedDB can. The guard reads the selected backend's capabilities - it does not test the provider name, so a new backend inherits the rule for free.

Live

This session supports multi-database transactions: yes

csharp Guarding on capability
var limits = session.Connection.RuntimeLimits;
if (!limits.SupportsMultiDatabaseTransactions)
{
    // Refused before it runs, by capability - not by provider name.
    return;
}

await Database.ExecuteNonQueryAsync("ATTACH DATABASE 'other.db' AS other");

Changing the page size

Block-oriented backends pin the page size to their block size - IndexedDB batch-atomic is the usual case. Letting the PRAGMA through would report success and then corrupt the image on the next write, so it is refused up front.

Live

This session can change page size: yes

csharp PRAGMA page_size
var limits = session.Connection.RuntimeLimits;
limits.CanChangePageSize;   // false on block-oriented backends

// Letting PRAGMA page_size through on a backend that pins it would report success and
// then corrupt the image, so BsqliteFeatureGuards throws instead.
await Database.ExecuteNonQueryAsync("PRAGMA page_size=512");
An unhandled error has occurred. Reload 🗙