@nudata/nu-duck-df
v0.4.1
Published
A framework-agnostic in-browser analytics stack built on [DuckDB-wasm](https://duckdb.org/docs/api/wasm/overview). Query engine, notebook, DataFrame API — no server, no framework lock-in.
Downloads
329
Readme
@nudata/nu-duck-df
A framework-agnostic in-browser analytics stack built on DuckDB-wasm. Query engine, notebook, DataFrame API — no server, no framework lock-in.
npm i @nudata/nu-duck-dfOr drop it into any page via CDN:
<script src="https://cdn.jsdelivr.net/npm/@nudata/nu-duck-df/dist/nu-duck-df.iife.js"></script>
<script>
nu_df.setup().then((db) => console.log('DuckDB ready', db))
</script>What you get
A four-layer stack, each layer usable on its own:
| Layer | Class | Role |
|----------------|-----------------|------|
| Database | NuDuckDb | Connection + catalog + SQL execution. Load tables from JSON, URLs, files, or Arrow; create views; run prepared statements; export to CSV/JSON; persist the catalog to localStorage; optionally route queries to a remote DuckDB HTTP endpoint. |
| Table metadata | NuTable | Lightweight wrapper for a single table or view — columns, row count, summarize(), sample(), source tracking. |
| Workbook | NuWorkbook | Notebook with markdown / SQL / JS cells, localStorage persistence, export/import, and linked-table restoration. |
| DataFrame | NuDataFrame | Lazy, immutable, chainable DataFrame that compiles to readable DuckDB SQL (CTE per step). Full DuckDB extensions surface — EXCLUDE, REPLACE, QUALIFY, PIVOT, ASOF JOIN, SUMMARIZE, etc. |
DuckDB-wasm is bundled — no separate CDN tag for the engine.
Quick start
ES module (bundler / Vite / webpack)
import { setup } from '@nudata/nu-duck-df'
const db = await setup()
await db.addTableFromUrl('orders', '/data/orders.parquet')
const rows = await db.query('SELECT region, SUM(amount) AS total FROM orders GROUP BY region')
const t = db.getTable('orders')
console.log(t.rowCount, t.columnNames())DataFrame chain
import { setup } from '@nudata/nu-duck-df'
const db = await setup()
await db.addTableFromUrl('orders', '/data/orders.parquet')
const top = await db
.table('orders')
.filter("status = 'paid'")
.groupBy('region')
.agg({ total: 'sum(amount)', n: 'count(*)' })
.orderBy('total desc')
.limit(10)
.collect()compileSql() on any DataFrame returns the readable CTE-based SQL it would run.
Workbook
import { setup, NuWorkbook } from '@nudata/nu-duck-df'
const db = await setup()
const wb = new NuWorkbook({ db, name: 'sales-exploration' })
wb.addCell({ kind: 'markdown', source: '# Sales by region' })
wb.addCell({ kind: 'sql', source: 'SELECT region, SUM(amount) AS total FROM orders GROUP BY region' })
wb.addCell({ kind: 'js', source: 'return db.table("orders").rowCount' })
await wb.executeAll()
await wb.save()Public API
import {
setup, // singleton initialiser; returns a ready NuDuckDb
NuDuckDb, // direct instantiation for multi-db use cases
NuTable,
NuWorkbook,
NuDataFrame,
GroupedNuDataFrame,
exportRows,
rowsToCsv,
} from '@nudata/nu-duck-df'The IIFE build exposes everything under window.nu_df (nu_df.setup(),
nu_df.NuDataFrame, etc.).
Status
| Milestone | Scope | Status |
|-----------|-------|--------|
| M1 | Core DB layer — init, tables, views, queries, remote mode | shipped (0.2.0) |
| M2 | Catalog completeness — files, persistence, events, Arrow, export | shipped (0.3.0) |
| M3 | Workbook — markdown + SQL cells, persistence, export/import | shipped |
| M4 | DataFrame layer — lazy chain → DuckDB SQL | shipped (0.4.0) |
| M5 | Workbook ↔ Table linking — restorable workbooks | shipped |
| M5.5 | Workbook polish — JS cells, resize, untrusted-import guard | in progress |
| M6 | UI components — framework-agnostic slicers / displays | pending |
Full detail and exit criteria in product/roadmap.md and
product/milestones.md. Vision and market context in
product/vision.md.
Develop
yarn install
yarn test # 441+ unit tests (Vitest)
yarn build # builds dist/ (ES + UMD + IIFE)
yarn build:watch # rebuild on savePlaygrounds
yarn playground # vanilla Vite app — playground/
yarn playground:react # React dev app — playground/react/
yarn playground:consumer # React app pulling from dist/ — package smoke testBy default the playgrounds alias @nudata/nu-duck-df directly to src/index.js
for HMR. See playground/README.md for switching to the
built package via file:.. to verify the published artefact.
Build outputs
dist/nu-duck-df.js ES module (import)
dist/nu-duck-df.umd.cjs UMD (require)
dist/nu-duck-df.iife.js IIFE — window.nu_df for <script> tag / CDNRequires Node 20+ for development. Targets the last two versions of Chrome, Firefox, and Safari at runtime.
License
MIT.
