A Database in your Browser in sqlite3 Steps

What follows is a demonstration of how to get sqlite3 up and running in a browser1 in a few brief steps. For simplicity's sake, this tutorial will demonstrate loading the sqlite3 JavaScript/WebAssembly (WASM) module in the so-called main thread of a web page. Using the module from a worker requires only a small bit more effort and will be covered in a later tutorial, as will how to make use of various persistent-storage options.

Before we begin, be aware of the following limitations of the approach demonstrated here:

Step 1: Create the HTML

At its most basic, we need HTML scaffolding which loads both the main sqlite3.js and a client application which uses it. For example:

<!doctype html>
<html lang="en-us">
    <meta charset="utf-8">
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <title>Hello, sqlite3</title>
    <script src="jswasm/sqlite3.js"></script>
    <script src="demo-123.js"></script>

See demo-123.html for one with slightly more flavor.

Step 2: Create a JS App

With the HTML out of the way, we need our JavaScript application. The most fundamental part is the loading of the WASM-compiled form of the library and initialization of its JavaScript binding. That is all performed via a routine exported by sqlite3.js:

  // The module is now loaded and the sqlite3 namespace
  // object was passed to this function.
  console.log("sqlite3:", sqlite3);

See demo-123.js for a "full-featured" example and demonstration of the high-level sqlite3 JS API.

The sqlite3InitModule() function is the only global symbol exported by the sqlite3 WASM module loader and it must be called only a single time in any application. It is the application's responsibility to store the sqlite3 object wherever is convenient for the application. At its most simplest:

globalThis.sqlite3 = sqlite3;

will install it as a global symbol2, but such use of the global scope is discouraged in most projects.

Note that on a slow connection, downloading the WASM file (a step triggered by sqlite3InitModule()) may take some time, during which the demo will appear to be inactive. The application may add additional HTML, CSS, and JS bits in order to receive notifications about the loading status so that, for example, the UI can show a "loading..." animation or report any errors. Doing so requires becoming familiar with the Emscripten-provided JS/WASM scaffolding and is beyond the scope of this demonstration. An example is available at the bottom of the sqlite3 fiddle application.

Step 3: The Web Server

With the HTML and JS in place, we require a web server in order to run them. Due to security limitations, browsers may refuse to load WASM from pages served via file:// URLs. As the web server is largely a matter of personal preference, and many options are available, getting that part running is out of scope here.

In short, we need the following files to be the same directory on some arbitrary web server:

With the web server up and running, we simply need to point our browser to the location of the demo file(s):

  1. ^ A recent (post-2020), full-featured browser is required. Firefox and the Chrome family of browsers are known to be sufficient on most platforms. This framework currently targets only browsers, not non-browser runtimes such as node.js.
  2. ^ The symbols globalThis and self refer to the global object in the main thread and Worker threads. The name globalSelf is more portable to non-browser platforms and is supported in all JS-relevant browsers.