Storage adapter using IndexedDB + sql.js for client-side SQL persistence.

The Key Difference: Automatic Persistence

sql.js adapter alone:

  • In-memory SQLite database (lost on page refresh)
  • You must manually call db.export() and save it yourself
  • No automatic persistence in browsers
  • Good for: Edge functions, temporary calculations, prototyping

IndexedDB adapter (this):

  • Same sql.js SQL engine, but automatically saves to IndexedDB
  • Data survives page refreshes automatically
  • Auto-save batching reduces overhead
  • Good for: Production PWAs, offline-first apps, persistent client-side storage

Is This Necessary?

✅ YES if you need:

  • Data to survive page refreshes (production apps)
  • Offline-first functionality (PWAs)
  • Privacy-first apps (data never leaves browser)
  • Zero manual save logic (just works)

❌ NO if you:

  • Only need temporary/in-memory data (edge functions)
  • Are prototyping and don't care about persistence
  • Want to manually control when data is saved
  • Don't need data to survive refreshes

Alternative: You could use sql.js directly and manually save to IndexedDB yourself, but you'd lose:

  • Automatic batched saves (performance optimization)
  • Reliable persistence (easy to forget manual saves = data loss)
  • Consistent API across platforms
  • Production-ready defaults

Bottom line: This adapter is necessary for production web apps that need persistence. For prototypes or edge functions, sql.js alone is fine.

How It Works:

  1. IndexedDB stores the SQLite database file (binary blob) - this is just storage
  2. sql.js (WASM) loads the database into memory and executes SQL - this provides SQL capabilities
  3. After writes, the updated database is automatically saved back to IndexedDB

Why IndexedDB + sql.js?

  • IndexedDB alone: NoSQL key-value store, no SQL support
  • sql.js alone: In-memory SQL, but no automatic persistence (you must manually save)
  • Combined: Full SQL + automatic browser-native persistence = production-ready solution

Capabilities:

  • ✅ Transactions (via sql.js)
  • ✅ Persistence (via IndexedDB - automatic!)
  • ✅ Full SQL support (via sql.js)
  • ✅ Export/import
  • ❌ Concurrent writes (single-threaded)
  • ❌ Server-side (browser only)

Performance:

  • Fast reads (in-memory SQL)
  • Moderate writes (IndexedDB persistence)
  • Auto-save batching reduces IDB overhead
const adapter = new IndexedDbAdapter({ dbName: 'my-app-db' });
await adapter.open();
await adapter.run('CREATE TABLE sessions (id TEXT PRIMARY KEY, data TEXT)');

Implements

Constructors

Properties

kind: "indexeddb" = 'indexeddb'

Identifier for logging/diagnostics (e.g., 'better-sqlite3', 'postgres').

capabilities: ReadonlySet<StorageCapability> = ...

Capability flags indicating supported features.

Methods

  • Begins a transaction. sql.js executes all statements in implicit transactions, so this is a no-op for compatibility.

    Returns Promise<void>

  • Exports the database as a Uint8Array (SQLite file format). Can be downloaded or stored externally.

    Returns Uint8Array

    SQLite database file as binary

  • Imports a database from a Uint8Array (SQLite file). Replaces the current database.

    Parameters

    • data: Uint8Array

      SQLite database file

    Returns Promise<void>