Intro To WASM DuckDB


You want to use DuckDB WASM in-browser and just need to know how to start.


Take advantage of the work of folks from Carnegie Mellon and Observable to make working with DuckDB on the web painless and fun!


The folks at DuckDB write great documentation, and their section on DuckDB WASM is a solid resource when paired with their many examples. But, folks from CMU and Observable made working with DuckDB WASM in a browser context nearly as straightforward as working with the CLI, so this section of the book will focus on using Observable’s DuckDBClient.

To level the playing field, we’re also going to work with it in-browser, with vanilla JS, sourcing packages from JSDelivr, a free, global, content delivery network (CDN). No “NPM”. No “Vite”. This way, we can focus soley on DuckDB (and, some other goodies from Observable, and other places).

The chapters in this section will be in the same Problem/Solution/Discussion format, covering some common idioms you will likely want to implement with DuckDB WASM. We’ll start with the MVDWC: minimum viable DuckDB WASM code to bring the power of this revolutionary database to your browser.

🔵 DuckDB loading…

There should be two lines above this paragraph. One should say “🟢 DuckDB loaded!” and the other should say “Hello, World!”. If not, you may need to check your browser’s JavaScript settings.

The “loading/loaded” message is a way to let folks know that the DuckDB WASM package is being downloaded and instantiated in-browser. Most folks may not have even seen the “loading” message, but folks with slower internet connections will appreciate knowing what’s going on.

The greeting below the message is built from querying an in-browser DuckDB database that has a table built from an array of objects.

Here’s the complete code. First, this is the HTML that sets up the loading and message blocks:

<p><span id="loader">🔵 DuckDB loading…</span></p>
<p id="msg"></p>

And, this is the entirety of the JavaScript that’s running on this page to fill in those placeholders:

<script type="module">
1import { Library } from '';
2const { DuckDBClient } = new Library()

4const db = await DuckDBClient().of({
  sample: [
    { msg: "Hello"},
    { msg: "World!"}

3document.getElementById("loader").innerHTML = "🟢 DuckDB loaded!"

5document.getElementById("msg").innerHTML = [
  ...await db.sql`SELECT msg FROM sample`
].map(d => d.msg).join(", ")
This brings in the Observable Standard Library, which contains the DuckDBClient we’ll be using.
This makes the DuckDBClient available to this browsers object namespace.
This changes the “loading” message after both the library has been fully imported, DuckDB WASM components have been downloaded, cached, and we’ve loaded in some data to the database.
This loads an array of objects as a table into our DuckDB instance. Don’t worry, we’ll talk about that in future chapters.
This makes a query, converts the output into something we can use in a normal JavaScript context, and makes a message that we show to the readers.

The next few chapters will focus on the types of data you can load into a DuckDB WASM context and how to do so.