duckviz
v0.3.2
Published
DuckViz CLI: scaffold starter apps and send local files to the DuckViz web app
Maintainers
Readme
duckviz
Two subcommands:
npx duckviz create-app <name>— scaffold a Next.js starter wired to the DuckViz packages (Explorer, Dashboard, Report, Deck) with the SDK proxy already set up so yourDUCKVIZ_TOKENnever reaches the browser.npx duckviz <paths...>— push local files to the DuckViz web app from your terminal. The bytes never leave your machine — DuckViz fetches them directly from a one-shot loopback server the CLI runs on127.0.0.1.
create-app — scaffold a starter
npx duckviz create-app my-app # default: --template=nextjs, auto-detects pm
npx duckviz create-app my-app --pm=bun # force a package manager
npx duckviz create-app my-app --no-install # skip `npm install` after copy
npx duckviz create-app my-app --no-git # skip `git init`
npx duckviz create-app my-app --force # overwrite a non-empty target dirThe nextjs template ships:
- Next.js 15 + Tailwind v4, App Router.
app/api/users— demo endpoint returning fake user rows for ingest.app/api/duckviz/[...route]— SDK proxy. ReadsDUCKVIZ_TOKENfrom.env.localand forwards browser AI calls upstream with the bearer attached.lib/custom-fetch.ts— rewrites/api/*→/api/duckviz/*so Explorer / Report / Deck calls hit the proxy instead of 404'ing on your origin.lib/demo-dashboard.ts— 4-widget demo (KPI, KPI, bar, line) against thet_userstable.app/dashboard,app/explorer,app/report,app/deck— one route per surface, all sharing the sameuseUsersDataset()hook.
After cd my-app, drop your token into .env.local:
DUCKVIZ_TOKEN=dvz_live_...…then npm run dev (or your pm's equivalent).
duckviz <paths...> — push files to the live app
npx duckviz # prints --help (no path → no ingest)
npx duckviz . # files in current dir (top-level only)
npx duckviz ./logs # files in ./logs (top-level only)
npx duckviz ./logs -r # ./logs recursively
npx duckviz sales.csv # single file
npx duckviz a.csv b.csv # multiple files
npx duckviz ./logs --fresh # replace any existing session in the browser
# (default: append to active session)
npx duckviz . --url http://localhost:3001 # point at a local dev serverFlags
| Flag | Default | Description |
| -------------------- | --------------- | ------------------------------------------------------ |
| -r, --recursive | off | Recurse into subdirectories |
| --fresh | off | Replace any existing browser session (default: append) |
| --url <url> | app.duckviz.com | DuckViz web app URL |
| --port <port> | random | Pin the local server port |
| --no-open | off | Print URL instead of opening the browser |
| --ignore <pattern> | — | Extra ignore pattern (repeatable) |
File selection
- Allowlist:
csv, tsv, json, ndjson, xlsx, xml, log, txt, parquet - Hidden files (starting with
.) are always skipped .gitignorepatterns are respected when present- Folders are non-recursive by default — pass
-rto walk subdirectories
How it works
- CLI walks the path, builds a manifest of matching files.
- CLI starts an HTTP server on
127.0.0.1:<random>with a one-time bearer token. - CLI opens
https://app.duckviz.com/cli-receive?endpoint=…&token=…in your browser. - The web app fetches the manifest and downloads each file from the loopback server straight into DuckDB-WASM. No bytes go through DuckViz servers.
- The CLI exits once the browser reports done.
The local server only listens on the loopback interface, requires the bearer token on every request, restricts CORS to the DuckViz origin, and shuts down after 10 minutes of inactivity.
