tech-book-labs
データ基盤(クライアント完結) · 最終検証 2026-05-26 · @duckdb/duckdb-wasm 1.33.x · 初公開 2026-05-10

DuckDB-Wasm でブラウザ内 SQL を動かす

DuckDB-Wasm をブラウザに埋め込み、SQL の DDL / INSERT / SELECT をクライアント完結で実行するパターン。getJsDelivrBundles の中身、SharedArrayBuffer + COOP/COEP ヘッダ、4GB の memory 上限、Parquet を URL 直読みする時の CORS 罠まで実装メモ。

duckdb wasm sql browser-analytics

検証日: 2026-05-26

使用バージョン: @duckdb/duckdb-wasm@1.33.x(2026-05 時点で main)

対象: ブラウザだけで分析クエリを動かしたい(サーバー不要)、Parquet を直接読みたい、ローカル CSV 解析

DuckDB(列指向の高速分析 SQL DB)を WASM(WebAssembly) ビルドでブラウザに埋め込み、サーバーなしで SQL を実行するパターン。DDL / INSERT / SELECT / Parquet 読み込み、WASM ロードの落とし穴を動く demo で確認します。

触って試す

🦆 DuckDB-Wasm が初回 ~3MB の wasm を fetch します。読み込み完了後に実行できます。

初回は WASM(~3MB)を fetch するため数秒待ちます。

セットアップ(npm + 3 種類の WASM bundle)

npm i @duckdb/duckdb-wasm
項目
公開バージョン1.33.x(DuckDB native ~1.3 系に対応)
Node 必要バージョン18+(主用途はブラウザ)
TypeScript 型本体同梱
ブラウザ要件WebAssembly + Web Worker + SharedArrayBuffer(eh bundle 使用時)
WASM サイズ3MB 前後(mvp < eh < coi)、main bundle に同梱厳禁
ライセンスMIT

DuckDB-Wasm は環境別に 3 種類の WASM bundle(mvp / eh / coi)を持っていて、getJsDelivrBundles()selectBundle()ブラウザの capability から自動選択する:

bundle速度必要なブラウザ機能
mvp最も遅いWebAssembly のみ(古いブラウザの fallback)
eh速いWebAssembly Exception Handling
coi最速SharedArrayBuffer + Cross-Origin Isolation(COOP/COEP ヘッダ要)

coi を使うには HTTP レスポンスに 2 つのヘッダ が必要:

Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp

Cloudflare Pages / Workers / Vercel いずれもヘッダは _headers ファイル(Pages)や Response.headers で設定可能。iframe 内に埋め込む場合は 親ページも同じヘッダ必須(さもないと eh にフォールバック)。

なぜブラウザで SQL?

  • サーバー / DB 不要:プライベートデータをアップロードせず、ローカルで分析できる
  • Parquet を直接読める:CSV や JSON より高速、列志向で集約に強い
  • OLAP 系クエリ最適化:GROUP BY / WINDOW / JOIN が Postgres 互換 + 高速
  • AI agent との相性:LLM に SQL を書かせて即実行する UX

代替: SQL.js(SQLite を WASM 化)。OLAP / Parquet なら DuckDB のほうが速い。

最小サンプル(DuckDB-Wasm 1.33、5 ステップ)

AsyncDuckDB を bundle に応じた worker と一緒に初期化、connect() でコネクションを取って query() を実行するだけ:

import * as duckdb from "@duckdb/duckdb-wasm";

const bundles = duckdb.getJsDelivrBundles();
const bundle = await duckdb.selectBundle(bundles);
const worker = new Worker(bundle.mainWorker!);
const db = new duckdb.AsyncDuckDB(new duckdb.ConsoleLogger(), worker);
await db.instantiate(bundle.mainModule, bundle.pthreadWorker);

const conn = await db.connect();
await conn.query(`
  CREATE TABLE sales (region TEXT, revenue DOUBLE);
  INSERT INTO sales VALUES ('east', 1500), ('west', 1100);
`);

const result = await conn.query("SELECT region, SUM(revenue) FROM sales GROUP BY region");
console.log(result.toArray());

Parquet / CSV を直接読む

registerFileURL で URL を登録 → SQL から read_csv / read_parquet で直接読める:

// HTTP 経由で Parquet を直接 SQL 対象にできる
const r = await conn.query(`
  SELECT category, COUNT(*)
  FROM 'https://example.com/data.parquet'
  GROUP BY category
`);

// ローカル CSV(ユーザがアップロードした File を Blob URL 化)
const file = inputElement.files![0];
await db.registerFileHandle("upload.csv", file, duckdb.DuckDBDataProtocol.BROWSER_FILEREADER, true);
await conn.query("SELECT * FROM 'upload.csv' LIMIT 10");

バンドル戦略

WASM は ~3MB あるので、main bundle に同梱しない。動的 import で初回利用時にだけロード:

const init = async () => {
  const duckdb = await import("@duckdb/duckdb-wasm");
  // ...
};

getJsDelivrBundles() は CDN(jsdelivr)からブラウザ環境ごとに最適な bundle を選んでくれる。自前 host する場合は bundles を手動で用意。

主な SQL 機能

機能サポート
GROUP BY / 集約
JOIN(全種類)
WINDOW 関数✅(LEAD / LAG / RANK / ROW_NUMBER)
CTE / 再帰 CTE
Date / Timestamp 関数✅(date_trunc / interval)
JSON 関数✅(json_extract)
Geospatial△(spatial extension で対応)

PostgreSQL 互換が高く、Postgres で書いた analytic クエリはほぼそのまま動く。

Parquet を URL から直読みする 3 つの前提

SELECT * FROM 'https://example.com/data.parquet' の 1 行で外部 Parquet を読めるのは強力だが、現実は CORS と Range request が前提:

  1. Access-Control-Allow-Origin: 別ドメインの Parquet を読むなら必須。S3 / GCS / R2 は bucket の CORS 設定で許可
  2. Accept-Ranges: bytes: DuckDB は Parquet の footer から先に読むため、サーバが HTTP Range request に応える必要がある。Cloudflare R2 / S3 はデフォルトで対応、自前 nginx は chunked_transfer_encoding off 等の調整が必要
  3. HTTPS: crossOriginIsolated 環境では mixed content 不可

ローカル CSV を読ませる場合は registerFileHandle で File を渡すだけで OK(CORS の話は出てこない):

await db.registerFileHandle("upload.csv", file, duckdb.DuckDBDataProtocol.BROWSER_FILEREADER, true);
await conn.query("CREATE TABLE t AS SELECT * FROM 'upload.csv'");

7 つの落とし穴と直し方

症状原因直し方
coi bundle に切り替わらず体感遅いCOOP/COEP ヘッダ未設定SharedArrayBuffer 不使用host の HTTP ヘッダに COOP/COEP 設定。iframe で読むなら親も同じヘッダ
Parquet を読むと CORS エラーCORS / Range request 未設定S3 / R2 の CORS allow origin と Accept-Ranges: bytes を確認
Out of Memory で死ぬWASM の 4GB 上限(32-bit)Parquet を read_parquet('url', file_row_group_size=100000) で chunk 読み、または server 側で集約
UI がガクッと止まるsync DB を使っている / worker を使っていないAsyncDuckDB + worker を必ず使う(new duckdb.AsyncDuckDB(logger, worker))
列が全部 VARCHAR で推論されるCSV 型推論が ambiguousread_csv_auto('upload.csv', columns={'age': 'INT'}) で明示、もしくは CAST
初回 fetch が 3 秒以上かかるWASM が main bundle で同梱されない / preload なし<link rel="preload" as="fetch" type="application/wasm" crossorigin> で予読、または dynamic import で route 単位
クエリ結果が JS 側で BigInt で来るDuckDB の BIGINT は JS 上 BigIntresult.toArray() で受けた後 Number(row.x) で変換、もしくは SQL で CAST AS INT

評価

観点評価コメント
クエリ性能OLAP に最適化、数百万行も実用速度
Parquet サポート直接 URL から読める
バンドルWASM ~3MB、動的 import 必須
学習コストSQL 既知者なら API は薄いラッパー
エコシステムObservable Notebook / MotherDuck で連携進行中

向く / 向かないケース

  • 向く: ブラウザ内 BI ダッシュボード、ユーザがアップロードした CSV/Parquet の分析、エディタ内 query playground
  • 向かない: 数 GB のデータをクライアントで処理(memory limit)、リアルタイム書き込みの DB 用途
  • 向かない: 単純な「SQLite で十分」(SQL.js のほうがバンドル軽い)

関連 Topic / 関連書籍

この記事と関係する tech-book.net の Topic と、それぞれの Topic に紐づく書籍:

tech-book.net /books/9784297144944

JavaScriptによるはじめてのアルゴリズム入門 | tech-book.net

河西 朝雄

関連テーマ・学習ロードマップから次の一冊へ。

詳細を tech-book.net で見る
tech-book.net /books/9784873118086

Python と JavaScriptではじめるデータビジュアライゼーション | tech-book.net

Kyran Dale/嶋田 健志/木下 哲也

関連テーマ・学習ロードマップから次の一冊へ。

詳細を tech-book.net で見る
tech-book.net /books/9784839966645

React Native+Expoではじめるスマホアプリ開発 : JavaScriptによるアプリ構築の実際 | tech-book.net

松澤 太郎

関連テーマ・学習ロードマップから次の一冊へ。

詳細を tech-book.net で見る
tech-book.net /books/9784627857216

はじめてのWebデザイン&プログラミング : HTML、CSS、JavaScript、PHPの基本 | tech-book.net

村上 祐治

関連テーマ・学習ロードマップから次の一冊へ。

詳細を tech-book.net で見る
tech-book.net /books/9784297138714

フロントエンドの知識地図ーー 一冊でHTML/CSS/JavaScriptの開発技術が学べる本 | tech-book.net

株式会社ICS 池田 泰延/西原 翼/松本 ゆき

関連テーマ・学習ロードマップから次の一冊へ。

詳細を tech-book.net で見る