It's sqlite3
built for the web! (:warning: experimental :warning:)
sqlite3.js
is build of sqlite3
targetting the web, using WebAssembly
.
We compile from the official sqlite3
amalgamation file, using emcc
, to a standalone .wasm
file [1] [2] This works because sqlite3
itself is pretty self-contained and do not
have many (any?) dependency on external environment. To that end, we even omit the default operating system bindings
that sqlite3 ships with [unix] [windows]
and provide our own binding for the wasm
environment (that utilizes wasi
) and ship a custom build of sqlite3
.
sqlite3
built this way contains the default memdb
. We allow the user to pass in a serialized copy of the database as an ArrayBuffer
and load it into memory.
We also provide an HTTP Range-Request based read-only virtual filesystem
, inspired from phiresky/sql.js-httpvfs
.
The inner working of this system is significantly different as it's implemented as an actual virtual filesystem
, providing a more tight integration with sqlite3
, without depending on any Posix capabilities.
Future plans are to include more utilities and ship with more community extensions 🙌
Although technically possible, you should always try to import and use sqlite3.js
from within a Worker
instance only.
This is because sqlite3
's API is synchronous and will block the main browser thread causing sluggish UI performance, or even crashes.
// ... in a Web Worker
importScript('https://cdn.jsdelivr.net/gh/riyaz-ali/sqlite3.js@<release>/dist/sqlite3.js')
await sqlite3.load(file => `https://cdn.jsdelivr.net/gh/riyaz-ali/sqlite3.js@<release>/dist/${file}`)
// open a new connection
let connection = new sqlite3.open(); // opens a new in-memory connection
// let's try out a query
let stmt = connection.prepare("SELECT DATE('now') AS now");
stmt.step();
stmt.columns(); // returns ["now"]
stmt.get(); // returns ["2021-02-18"] as of date of writing...
You can also pass an existing database to sqlite3.open()
call, and / or also download a serialized copy later.
// ... assuming initialization is already done
// fetch a serialized copy of the chinook database
const chinook = await fetch('...').then(resp => resp.arrayBuffer());
let connection = new sqlite3.open(chinook);
let stmt = connection.prepare('SELECT * FROM employee');
while(stmt.step()) { console.log(stmt.get()) } // will print out each row to console
stmt.finalize(); // close the statement handle
const buffer = connection.serialize();
// ... buffer is an ArrayBuffer containing serialized copy of the database file