DuckVizBeta
Packages

@duckviz/db

DuckDB-WASM engine with React context, file ingestion, persistence, and SQL queries.

@duckviz/db provides a React context that wraps DuckDB-WASM. It handles engine initialization, file ingestion, SQL queries, IndexedDB persistence, and table management — all running in a Web Worker so the main thread stays responsive.

Installation

npm install @duckviz/db @duckdb/duckdb-wasm apache-arrow

Quick start

import { DuckvizDBProvider, useDuckDB } from "@duckviz/db";

// 1. Wrap your app
function App() {
  return (
    <DuckvizDBProvider persistence batchSize={5000}>
      <MyComponent />
    </DuckvizDBProvider>
  );
}

// 2. Use the hook
function MyComponent() {
  const db = useDuckDB();

  async function loadData() {
    await db.ingest({
      rows: [{ name: "Alice", age: 30 }, { name: "Bob", age: 25 }],
      tableName: "t_users",
    });
    const result = await db.runQuery("SELECT * FROM t_users");
    console.log(result);
  }

  if (db.loading) return <p>Booting DuckDB...</p>;
  return <button onClick={loadData}>Load data</button>;
}

<DuckvizDBProvider>

The provider initializes DuckDB-WASM and makes it available to child components via context.

Prop

Type

defaultRowCap was added in @duckviz/db@0.6.0; the non-SELECT skip fix landed in 0.6.1. See Performance for sizing guidance.

useDuckDB()

Returns the DuckDBContextValue object. Throws if used outside a <DuckvizDBProvider>.

State properties

Prop

Type

Ingestion methods

Prop

Type

Query methods

Prop

Type

Persistence methods

Prop

Type

useDuckDBOrNull()

Same as useDuckDB(), but returns null instead of throwing when used outside a provider. Useful for components that can optionally use DuckDB.

useAutoIngest()

Hook that auto-ingests row data into DuckDB on mount. Used internally by <Dashboard>, <Explorer>, <ReportBuilder>, and <DeckBuilder> — call it directly if you're composing your own UI.

import { useAutoIngest, type DuckvizDataset } from "@duckviz/db";

const datasets: DuckvizDataset[] = [
  { name: "Orders", data: orderRows },              // table: t_orders
  { name: "Users", data: userRows, tableName: "t_users" },
];

function MyComponent() {
  const { ready, ingesting, error } = useAutoIngest({
    datasets,
    dropOnUnmount: true, // default
  });

  if (ingesting || !ready) return <p>Loading…</p>;
  if (error) return <p>Failed: {error}</p>;
  return <YourChart />;
}

Re-ingestion is keyed on a fingerprint of (tableName, rowCount) per dataset — stable references are not required. Handles React Strict Mode double-mount via a microtask-deferred drop.

DuckvizDataset

Shared dataset shape used by auto-ingest across all DuckViz component packages.

interface DuckvizDataset {
  name: string;                          // Display name, also used to derive tableName when omitted
  data: Record<string, unknown>[];       // Row data
  tableName?: string;                    // Explicit DuckDB table name (overrides pathToTableName(name))
}

pathToTableName()

Utility function that converts a file path to a valid DuckDB table name:

import { pathToTableName } from "@duckviz/db";

pathToTableName("sales_2024.csv");    // "t_sales_2024"
pathToTableName("logs/access.log");   // "t_access"
pathToTableName("data.json");         // "t_data"

Strips file extensions, adds a t_ prefix, and sanitizes special characters.

Exported types

// Column metadata
interface SchemaColumn {
  column_name: string;
  column_type: string;  // DuckDB type: VARCHAR, INTEGER, DOUBLE, etc.
}

// Table metadata
interface TableInfo {
  tableName: string;
  schema: SchemaColumn[];
}

Example: programmatic data seeding

import { useDuckDB } from "@duckviz/db";
import { useEffect, useRef } from "react";

function DataSeeder() {
  const db = useDuckDB();
  const seeded = useRef(false);

  useEffect(() => {
    if (db.loading || db.restoring || seeded.current) return;
    seeded.current = true;

    (async () => {
      // Check if table already exists (from persisted session)
      const exists = await db.tableExists("t_users");
      if (exists) return;

      // Fetch data from your API
      const res = await fetch("/api/users");
      const { users } = await res.json();

      // Ingest into DuckDB
      await db.ingest({ rows: users, tableName: "t_users" });

      // Now you can query it
      const topUsers = await db.runQuery(`
        SELECT name, revenue
        FROM t_users
        ORDER BY revenue DESC
        LIMIT 10
      `);
      console.log(topUsers);
    })();
  }, [db]);

  return null;
}