Installation To use the DuckDB Wasm client, visit the
duckdb-wasmGitHub repository.The latest stable version of the DuckDB WebAssembly client is 2.0.0.
DuckDB-Wasm is a version of DuckDB that has been compiled to WebAssembly, the portable binary format that browsers can run at near-native speed. This lets a full DuckDB engine run entirely inside any browser on any device, with no server to send queries to and no data leaving the user's machine.
It offers a layered API to fit different needs:
- embedded as a JavaScript + WebAssembly library
- used as a Web shell
- built from source
This page covers installation and basic usage; the other pages in this section cover instantiating the client, importing data, running queries, loading extensions, and deploying it.
Try It Yourself
The shell below is a full DuckDB engine running in your browser — type a SQL query and run it right here:
Note The shell above is itself built with DuckDB-Wasm. It is the
@duckdb/duckdb-wasm-shellpackage, one of the layered APIs listed above, running on top of the same DuckDB-Wasm library this page describes. Every query you type executes client-side in WebAssembly, with no server round-trip, so it is a live demonstration of what your own application gets when it embeds DuckDB-Wasm.
Installation
DuckDB-Wasm is published to npm as @duckdb/duckdb-wasm. Install it with your package manager:
npm install @duckdb/duckdb-wasm
This installs the current stable release (the latest tag). To try the newest, unreleased build instead, install the next tag with npm install @duckdb/duckdb-wasm@next; it tracks the main branch and is intended for testing rather than production.
Alternatively, load a prebuilt bundle directly from a CDN such as jsDelivr without installing anything; see Instantiate for the bundle-selection options. To try it interactively with no setup, use the DuckDB-Wasm Web shell.
Basic API Usage
The example below instantiates DuckDB-Wasm from a CDN bundle, opens a connection, runs a query, and reads the result. Instantiate covers the other ways to load the bundle, such as with webpack, Vite, or self-hosted files.
Refer to the externally hosted DuckDB-Wasm API Reference for details on every class and method. The DuckDB-Wasm launch blog post is another good introduction.
import * as duckdb from '@duckdb/duckdb-wasm';
// Instantiate DuckDB-Wasm from a jsDelivr bundle
const bundle = await duckdb.selectBundle(duckdb.getJsDelivrBundles());
// Worker scripts must be same-origin, so wrap the CDN worker in a Blob URL
const worker_url = URL.createObjectURL(
new Blob([`importScripts("${bundle.mainWorker}");`], { type: 'text/javascript' })
);
const worker = new Worker(worker_url);
const db = new duckdb.AsyncDuckDB(new duckdb.ConsoleLogger(), worker);
await db.instantiate(bundle.mainModule, bundle.pthreadWorker);
URL.revokeObjectURL(worker_url);
// Open a connection and run a query
const conn = await db.connect();
const result = await conn.query('SELECT 42 AS answer');
console.log(result.toArray()[0].answer); // prints 42
// Release resources
await conn.close();
await db.terminate();
await worker.terminate();
How DuckDB-Wasm Works
DuckDB-Wasm uses Apache Arrow as its data protocol for both data import and query results. Arrow is a columnar, database-friendly format that the apache-arrow npm package implements in the browser, letting DuckDB-Wasm exchange data efficiently and interoperate with other JavaScript data tools without reimplementing SQL type logic in JavaScript.
DuckDB-Wasm is built on a virtual filesystem that treats local files, remote HTTP(S) servers and in-memory buffers uniformly.
Because DuckDB understands file formats such as Parquet, it reads only the bytes a query needs rather than downloading an entire file: SELECT count(*) FROM 'file.parquet' can be answered from the file metadata alone, and selective filters or LIMIT … OFFSET clauses let entire row groups be skipped. This makes it practical to query large Parquet files hosted on a remote server directly from the browser.
Note This partial-read behavior depends on which httpfs path serves the request. The JavaScript httpfs implementation fetches only the required byte ranges, but reading through the built-in httpfs extension may currently download the whole file instead (see duckdb-wasm issue #2153).
Limitations
- By default, the WebAssembly client only uses a single thread. Multithreading is available but still experimental.
- The WebAssembly client has a limited amount of memory available. WebAssembly limits the amount of available memory to 4 GB and browsers may impose even stricter limits.
See Troubleshoot for workarounds when you run into these limits.
Further Reading
- Instantiate — the bundle-selection patterns for jsDelivr, webpack, Vite, and statically served files.
- Import Data — registering files and inserting Apache Arrow, CSV, JSON, and Parquet data.
- Run Queries — materialized and streaming queries, prepared statements, and exporting results.
- Load Extensions — how extension loading differs from native DuckDB and which extensions are available.
- Deploy — the components a deployment serves and the security considerations involved.
- Troubleshoot — common issues and their workarounds, including CORS errors, memory limits, and threading.
- Clients Overview — the other client APIs DuckDB provides alongside Wasm.