SkillAgentSearch skills...

SqliteWasmBlazor

Blazor Sqlite implementation with full EFCore and OPFS support

Install / Use

/learn @b-straub/SqliteWasmBlazor
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

SqliteWasmBlazor

The first known solution providing true filesystem-backed SQLite database with full EF Core support for Blazor WebAssembly.

License: MIT .NET NuGet GitHub Repo stars

Try the Live Demo - Experience persistent SQLite database in your browser! Can be installed as a Progressive Web App (PWA) for offline use.

About This Project

This is a non-commercial hobby project maintained in my spare time - no fixed update cycle or roadmap. However, "hobby" refers to time and commitment, not craftsmanship: the project is developed with professional standards including proper test coverage and attention to code quality.

Open source thrives on community involvement. The project grows through bug reports, feature requests, pull requests, and real-world feedback. If you're considering this for production use, I'd encourage you to contribute back - that's how open source stays alive, not through promises from a single maintainer, but through shared ownership.

Stability & Status

The public API surface is intentionally kept minimal to reduce the risk of breaking changes. While the API has been stable in practice, this project is pre-1.0: broader real-world feedback is needed before committing to long-term API guarantees. Contributions and usage reports help move toward that goal.

What's New

  • Raw Database Import/Export - Export and import complete .db files directly from/to OPFS with schema validation and automatic backup/restore on failure (details)
  • Multi-Database Support - Run multiple independent SQLite databases simultaneously in the same Web Worker, each with its own OPFS file, DbContext, and migration history. Supports cross-database references via loose Guid linking (details)
  • Multi-View Demo - Floating draggable/resizable dialog windows using lightweight JS interop on top of standard MudBlazor dialogs (details)
  • Incremental Database Export/Import - File-based delta sync with checkpoint management and conflict resolution for offline-first PWAs (details)
  • Database Import/Export - Schema-validated MessagePack serialization for backups and data migration (details)
  • Real-World Sample - Check out the Datasync TodoApp for offline-first data synchronization with SqliteWasmBlazor

Breaking Changes

  • v0.7.2-pre - SqliteWasmWorkerBridge is now internal. Use ISqliteWasmDatabaseService via DI instead:
    // Program.cs - add service registration
    builder.Services.AddSqliteWasm();
    
    // Components - inject the interface
    @inject ISqliteWasmDatabaseService DatabaseService
    
    // Replace SqliteWasmWorkerBridge.Instance.DeleteDatabaseAsync(...)
    // with:   DatabaseService.DeleteDatabaseAsync(...)
    

What Makes This Special?

Unlike other Blazor WASM database solutions that use in-memory storage or IndexedDB emulation, SqliteWasmBlazor is the first implementation that combines:

  • True Filesystem Storage - Uses OPFS (Origin Private File System) with synchronous access handles
  • Full EF Core Support - Complete ADO.NET provider with migrations, relationships, and LINQ
  • Real SQLite Engine - Official sqlite-wasm (3.50.4) running in Web Worker
  • Persistent Data - Survives page refreshes, browser restarts, and even browser updates
  • No Server Required - Everything runs client-side in the browser

| Solution | Storage | Persistence | EF Core | Limitations | |----------|---------|-------------|---------|-------------| | InMemory | RAM | None | Full | Lost on refresh | | IndexedDB | IndexedDB | Yes | Limited | No SQL, complex API | | SQL.js | IndexedDB | Yes | None | Manual serialization | | besql | Cache API | Yes | Partial | Emulated filesystem | | SqliteWasmBlazor | OPFS | Yes | Full | None! |

Public API

SqliteWasmBlazor exposes a stable public API for database management operations via dependency injection:

ISqliteWasmDatabaseService

The primary interface for database operations outside of EF Core:

public interface ISqliteWasmDatabaseService
{
    /// <summary>Check if a database exists in OPFS.</summary>
    Task<bool> ExistsDatabaseAsync(string databaseName, CancellationToken cancellationToken = default);

    /// <summary>Delete a database from OPFS.</summary>
    Task DeleteDatabaseAsync(string databaseName, CancellationToken cancellationToken = default);

    /// <summary>Rename a database in OPFS (atomic operation).</summary>
    Task RenameDatabaseAsync(string oldName, string newName, CancellationToken cancellationToken = default);

    /// <summary>Close a database connection in the worker.</summary>
    Task CloseDatabaseAsync(string databaseName, CancellationToken cancellationToken = default);

    /// <summary>Import a raw .db file into OPFS.</summary>
    Task ImportDatabaseAsync(string databaseName, byte[] data, CancellationToken cancellationToken = default);

    /// <summary>Export a raw .db file from OPFS.</summary>
    Task<byte[]> ExportDatabaseAsync(string databaseName, CancellationToken cancellationToken = default);
}

Usage in components:

@inject ISqliteWasmDatabaseService DatabaseService

@code {
    private async Task ResetDatabaseAsync()
    {
        // Delete and recreate database
        await DatabaseService.DeleteDatabaseAsync("MyApp.db");

        await using var context = await DbContextFactory.CreateDbContextAsync();
        await context.Database.MigrateAsync();
    }

    private async Task ExportAsync()
    {
        // Export raw .db file (closes DB for consistent snapshot, auto-reopens on next query)
        byte[] data = await DatabaseService.ExportDatabaseAsync("MyApp.db");
    }

    private async Task ImportAsync(byte[] data)
    {
        // Import raw .db file (validates SQLite header)
        await DatabaseService.ImportDatabaseAsync("MyApp.db", data);
    }
}

Other Public Types

| Type | Purpose | |------|---------| | SqliteWasmConnection | ADO.NET DbConnection for direct SQL access | | SqliteWasmCommand | ADO.NET DbCommand for query execution | | SqliteWasmDataReader | ADO.NET DbDataReader for result iteration | | SqliteWasmParameter | ADO.NET DbParameter for query parameters | | SqliteWasmTransaction | ADO.NET DbTransaction for transaction support | | IDBInitializationService | Tracks database initialization state and errors |

All internal implementation details (worker bridge, serialization, etc.) are encapsulated and not part of the public API.

Installation

NuGet Package

dotnet add package SqliteWasmBlazor --prerelease

Or install a specific version:

dotnet add package SqliteWasmBlazor --version 0.6.5-pre

Visit NuGet.org for the latest version.

From Source

git clone https://github.com/bernisoft/SqliteWasmBlazor.git
cd SqliteWasmBlazor
dotnet build

Quick Start

1. Configure Your Project

Program.cs:

using SqliteWasmBlazor;

var builder = WebAssemblyHostBuilder.CreateDefault(args);

// Add your DbContext with SqliteWasm provider
builder.Services.AddDbContextFactory<TodoDbContext>(options =>
{
    var connection = new SqliteWasmConnection("Data Source=TodoDb.db");
    options.UseSqliteWasm(connection);
});

// Register initialization service
builder.Services.AddSingleton<IDBInitializationService, DBInitializationService>();

// Register SqliteWasm database management service (for ISqliteWasmDatabaseService)
builder.Services.AddSqliteWasm();

var host = builder.Build();

// Initialize SqliteWasm database with automatic migration support
await host.Services.InitializeSqliteWasmDatabaseAsync<TodoDbContext>();

await host.RunAsync();

The InitializeSqliteWasmDatabaseAsync extension method automatically:

  • Initializes the Web Worker bridge
  • Applies pending migrations (with automatic migration history recovery)
  • Handles multi-tab conflicts with helpful error messages
  • Tracks initialization status via IDBInitializationService

2. Define Your DbContext

using Microsoft.EntityFrameworkCore;

public class TodoDbContext : DbContext
{
    public TodoDbContext(DbContextOptions<TodoDbContext> options) : base(options) { }

    public DbSet<TodoItem> TodoItems { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<TodoItem>(entity =>
        {
            entity.HasKey(e => e.Id);
            entity.Property(e => e.Title).IsRequired().HasMaxLength(200);
        });
    }
}

public class TodoItem
{
    public int Id { get; set; }
    public string Title { get; set; }
    public bool IsCompleted { get; set; }
    public DateTime CreatedAt { get; set; }
}

3. Use in Your Components

@inject IDbContextFactory<TodoDbContext> DbFactory

<h3>Todo List</h3>

@foreach (var todo in todos)
{
    <div>
        <input type="checkbox" @bind="todo.IsCompleted" @bind:after="() => SaveTodo(todo)" />
        <span>@todo.Title</span>
    </div>
}

@code {
    private List<TodoItem> todos = new();

    protected override async Task OnInitializedAsync()
    {
        await using var db = await DbFactory.CreateDbContextAsync();
        todos 
View on GitHub
GitHub Stars71
CategoryData
Updated2d ago
Forks9

Languages

C#

Security Score

95/100

Audited on Mar 27, 2026

No findings