# wa-sqlite: SQLite in the Browser with JavaScript VFS Storage

> wa-sqlite packages SQLite as WebAssembly and lets JavaScript implement its virtual filesystem, including IndexedDB and Origin Private File System examples. It fits browser applications that need SQLite semantics without assuming a native SQLite library is available.

**rhashimoto/wa-sqlite** — WebAssembly SQLite with support for browser storage extensions

- Repository: https://github.com/rhashimoto/wa-sqlite
- Stars: 1,421 · Forks: 113
- Language: JavaScript
- License: MIT
- Published: 2026-10-16 · Updated: 2026-10-16 · Language: en
- Canonical page: https://hysenlabs.com/projects/rhashimoto-wa-sqlite

## Why wa-sqlite Places SQLite Storage Behind JavaScript

wa-sqlite addresses a specific browser constraint. SQLite normally operates against files through its virtual filesystem interface, or VFS, while web applications do not have general access to an ordinary local filesystem. This project builds SQLite for WebAssembly and allows the VFS implementation to be written completely in JavaScript. That opens browser storage APIs such as IndexedDB and Origin Private File System to SQLite without requiring a native SQLite extension for every storage mechanism.

The intended users are developers building browser applications that need SQL queries, schema management, and SQLite database behavior but also need more control over persistence than an in-memory database provides. The project is also relevant to developers adding SQLite functionality through JavaScript, which the README identifies as the primary motivation for building wa-sqlite itself.

It is not simply a JavaScript translation of SQLite. The Makefile downloads SQLite source identified as `version-3.53.0`, compiles SQLite-related C files, and configures the Emscripten build for web and worker environments. JavaScript files provide adapters and VFS-related integration. The result is an ES6 module and WebAssembly build that exposes SQLite operations through wrappers. The package manifest points consumers at `src/sqlite-api.js` for the JavaScript API and includes generated artifacts under `dist`.

## Sync, Asyncify, and JSPI Build Selection

The library is offered in synchronous and asynchronous forms. The README says an asynchronous build is required when an asynchronous VFS extension is used. The demo exposes three Emscripten build types through its `build` parameter: `default`, `asyncify`, and `jspi`. This choice matters because storage APIs such as IndexedDB are asynchronous from JavaScript's perspective, while the default SQLite path is built around synchronous VFS calls.

The demo also exposes several VFS configurations. The documented values include `MemoryVFS`, `MemoryAsyncVFS`, `IDBBatchAtomicVFS`, `IDBMirrorVFS`, `AccessHandlePoolVFS`, `OPFSAdaptiveVFS`, `OPFSAnyContextVFS`, `OPFSCoopSyncVFS`, and `OPFSWriteAheadVFS`. If `config` is omitted, the demo uses SQLite's internal memory. The combination is therefore part of the application design, not a minor runtime preference.

This design creates a clear trade-off. A synchronous build may fit storage adapters whose VFS methods remain synchronous. An asynchronous build is needed when the VFS calls JavaScript asynchronous browser APIs. The repository describes the examples as proof-of-concept implementations, so selecting a VFS by name does not establish that every implementation has the same transaction, durability, or failure semantics. The VFS comparison linked from the README is the relevant place to distinguish their behavior before adoption.

## Loading the Prebuilt Package and Running a First Query

Most developers are directed to use the prebuilt artifacts in `dist`, so a local Emscripten toolchain is not required for an initial application. The README's API example loads `wa-sqlite/dist/wa-sqlite.mjs`, creates a SQLite factory from the resulting WebAssembly module, opens a database, executes SQL, and closes the handle. The following example is the first-use path documented by the project.

```javascript
import SQLiteESMFactory from 'wa-sqlite/dist/wa-sqlite.mjs';
import * as SQLite from 'wa-sqlite';

async function hello() {
  const module = await SQLiteESMFactory();
  const sqlite3 = SQLite.Factory(module);
  const db = await sqlite3.open_v2('myDB');
  await sqlite3.exec(db, `SELECT 'Hello, world!'`, (row, columns) => {
    console.log(row);
  });
  await sqlite3.close(db);
}

hello();
```

The expected visible result is the `Hello, world!` row logged by the callback. In this example, `open_v2` receives the database name `myDB`, but persistence still depends on the active SQLite VFS and its implementation. The README points to the `demo/hello` example for a more complete version that uses a virtual filesystem for persistent storage. The shorter example is therefore suitable for checking module loading and SQL execution, not for deciding whether browser persistence meets an application's durability requirements.

## Serving the Demo and Selecting Browser Storage

The repository can serve its demo from the source tree using the `start` script. The README specifically says to open the demo URL after starting the server.

```bash
yarn start
```

The documented URL is `http://localhost:8000/demo/?build=asyncify&config=IDBBatchAtomicVFS&reset`. This URL selects the `asyncify` build, chooses `IDBBatchAtomicVFS`, and includes `reset` to clear persistent storage. The demo also provides a benchmark page, but the README does not publish benchmark results, so none can be used here as an adoption criterion.

The URL parameters provide a practical way to compare implementations. The `config` parameter can select IndexedDB and OPFS variants, while the `build` parameter determines whether the SQLite runtime is synchronous, Asyncify-based, or JSPI-based. The demo editor executes a selected text region and restores its contents through browser `localStorage`. Those conveniences apply to the demo, not automatically to an application built with wa-sqlite.

For an application, the important distinction is between a database that lives only in memory and one that survives reloads. The documented `reset` parameter makes destructive testing easy, which is useful during development, but it also means the demo URL can erase persistent data when that parameter is present.

## Building wa-sqlite with Emscripten on Debian Linux

The documented source-build path uses Debian Linux tooling, `yarn`, Emscripten SDK 3.1.61 or later, and several command-line utilities. The README says compatibility with other platforms is unknown. The documented build sequence begins by confirming that `emcc` works, then cloning and installing the repository.

```bash
git clone git@github.com:rhashimoto/wa-sqlite.git
cd wa-sqlite
yarn install
make
```

The default build produces ES6 modules and WebAssembly, with synchronous and asynchronous builds using Asyncify and JSPI, under `dist`. The package manifest identifies Yarn as `yarn@4.17.1`, and its `start`, `test`, and documentation scripts are defined in `package.json`.

The build customization path is narrower than the usual claim that any application can rebuild the library freely. The README mentions Make arguments for changing build defines or flags, and names `sqwab` as a helper for building without a local build environment. It does not document a general deployment workflow for every supported host, nor does it claim that non-Debian platforms are supported. The `Makefile` also embeds build-time dependencies such as SQLite source and an extension-functions source archive, so a self-hosted build has more moving parts than simply copying a JavaScript file into a web page.

## Operational Boundaries, License, and Upgrade Work

The central limitation is that wa-sqlite does not remove the hard parts of browser databases. A VFS must map SQLite file operations onto browser storage while preserving locking, transaction, durability, and recovery behavior. IndexedDB and OPFS have different platform constraints, and the README does not claim that the proof-of-concept VFS implementations provide identical guarantees. The demo's benchmark link is a way to run comparisons, not evidence of any particular performance level.

The README also does not document rollback procedures for database migrations, backup, quota handling, or recovery after a browser storage failure. It does explain that `sqlite3.exec` is a convenience layer and points developers who need binding parameters, explicit column data types, or finer control to statement-level usage and the implementation. An application with complex query and migration requirements should review those APIs rather than treating `exec` as the complete interface.

wa-sqlite is distributed under the MIT License according to the package description. The README states that the MIT license applied as of 2023-02-10 and that existing licensees may continue under GPLv3 or switch to the new license. This is a licensing note, not legal advice. Maintenance signals are recent: the repository is not archived, the last push was on 2026-10-13, and v1.1.2 was released on 2026-08-11. Upgrades still require checking the chosen build, VFS, browser requirements, and any migration behavior because the README does not promise compatibility across every prior artifact.

## Conclusion

Browser applications needing local SQLite with custom JavaScript storage should evaluate wa-sqlite, while server-side projects and teams requiring a documented production migration path for virtual filesystems should first inspect their chosen VFS. The first verification should be persistence, transaction behavior, build type compatibility, and recovery semantics in the exact browser environment being targeted. The repository is not archived, its last push was on 2026-10-13, and v1.1.2 was released on 2026-08-11, but its examples remain described as proof-of-concept implementations.

## FAQ

### What is wa-sqlite used for?

wa-sqlite is a WebAssembly build of SQLite for JavaScript applications. It is intended for browser applications that need SQLite behavior and can use JavaScript virtual filesystems, including IndexedDB and Origin Private File System.

### How do I install or build wa-sqlite?

Most developers can use the prebuilt artifacts in `dist`. Building from source is known to work on Debian Linux, while compatibility with other platforms is unknown. It also needs `yarn`, Emscripten SDK 3.1.61 or later, and the tools listed in the README; the documented sequence is `yarn install` followed by `make`.

### Which wa-sqlite build supports asynchronous VFS extensions?

The README states that an asynchronous build is required for asynchronous extensions. Its documented build choices are `default`, `asyncify`, and `jspi`, with `asyncify` used in the example demo URL.

### Can wa-sqlite store a database in IndexedDB?

Yes. `IDBBatchAtomicVFS` and `IDBMirrorVFS` are listed as demo configurations. The README describes these as proof-of-concept VFS implementations, so their transaction and recovery characteristics should be checked before relying on them for application data.

## Sources

- [Issues](https://github.com/rhashimoto/wa-sqlite/issues)
- [License: MIT](https://github.com/rhashimoto/wa-sqlite/blob/master/LICENSE)
- [README](https://github.com/rhashimoto/wa-sqlite/blob/master/README.md)
- [Releases](https://github.com/rhashimoto/wa-sqlite/releases)
- [rhashimoto/wa-sqlite on GitHub](https://github.com/rhashimoto/wa-sqlite)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/rhashimoto-wa-sqlite
