Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/iterate/sqlfu/llms.txt

Use this file to discover all available pages before exploring further.

@sqlite.org/sqlite-wasm brings SQLite to the browser as a WebAssembly module. The createSqliteWasmClient adapter wraps an open sqlite-wasm database handle as an AsyncClient, giving you the same typed query surface you use on the server — just with promises at each call site.
1

Install dependencies

npm install sqlfu @sqlite.org/sqlite-wasm
2

Configure sqlfu

The browser cannot read migration files from disk at runtime — they must be bundled. Leave db out of the config; sqlfu uses definitions.sql for type generation and generates a migration bundle the app imports:
sqlfu.config.ts
import {defineConfig} from 'sqlfu';

export default defineConfig({
  definitions: './definitions.sql',
  migrations: './migrations',
  queries: './sql',
});
Generated wrappers are async by default, matching the sqlite-wasm adapter.
3

Write schema and queries

Add your schema to definitions.sql:
definitions.sql
create table notes (
  id integer primary key,
  title text not null,
  body text not null
);
Add a query to sql/queries.sql:
sql/queries.sql
/** @name listNotes */
select id, title, body
from notes
order by id desc;
4

Draft and generate

Run the authoring commands on your development machine:
npx sqlfu draft
npx sqlfu generate
sqlfu generate writes TypeScript wrappers into sql/.generated/ and the migration bundle into migrations/.generated/migrations.ts. Both are committed to your repo and bundled into the browser app.
5

Open the database and call your queries

Initialize the WASM module, open the database, wrap it with createSqliteWasmClient, and apply migrations before returning the client:
src/db.ts
import sqlite3InitModule from '@sqlite.org/sqlite-wasm';
import {createSqliteWasmClient} from 'sqlfu';

import {migrate} from './migrations/.generated/migrations.ts';
import {listNotes} from './sql/.generated/queries.sql.ts';

export async function openBrowserDatabase() {
  const sqlite3 = await sqlite3InitModule();
  const db = new sqlite3.oo1.DB('file:app.db?vfs=opfs');
  const client = createSqliteWasmClient(db);

  await migrate(client);

  return client;
}

export async function loadNotes() {
  const client = await openBrowserDatabase();
  return listNotes(client);
}

OPFS vs. in-memory storage

Use the opfs VFS to persist data across page reloads. OPFS requires a secure context (HTTPS or localhost) and the page must be served with the following headers:
Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp
const db = new sqlite3.oo1.DB('file:app.db?vfs=opfs');
OPFS is not supported in all browsers. Check caniuse.com for current support. Fall back to in-memory storage if OPFS is unavailable.

Async behavior

@sqlite.org/sqlite-wasm is asynchronous. All generated wrappers and client.all(...) calls return promises:
// await required
const notes = await listNotes(client);
const rows = await client.all({sql: 'select * from notes', params: []});

Browser considerations

  • The WASM binary is loaded asynchronously on first call to sqlite3InitModule(). Call it once and reuse the returned sqlite3 object.
  • OPFS access requires both the Cross-Origin-Opener-Policy and Cross-Origin-Embedder-Policy headers. Missing headers will cause a runtime error when opening an OPFS-backed database.
  • The migration bundle (migrations/.generated/migrations.ts) is idempotent and safe to run on every page load.

Adapters reference

The sqlite-wasm adapter snippet and the full compatibility matrix.

SQL migrations

Migration history, the generated bundle, and drift detection.

Build docs developers (and LLMs) love