Skip to main content
better-duck-tauri is a Tauri v2 plugin that exposes better-duck (embedded DuckDB) to the webview as a local analytics engine — not just a CRUD bridge. The Rust side registers the plugin on tauri::Builder with a chosen backend; the frontend talks to it through the @better-duck/tauri npm package, which wraps a fixed set of invoke commands.
This documents version 0.1.0-beta.8. The crate is beta: query, analytics, migration, and security features are implemented and tested; the arrow (Arrow IPC) command and Android CI are the pending edges.

Architecture

Three layers, with the plugin as the trust boundary between an untrusted webview and the embedded database:
  • Webview holds a Database handle and calls typed methods that invoke plugin commands.
  • Plugin validates every call against the Tauri capability (which commands are allowed) and the scope + Policy (which values those commands may use), then runs DuckDB work on a blocking task so the async runtime is never blocked.
  • DuckDB is compiled into the app via better-duck-core (vendored through better-duck-sys), so there is no system install to manage.

How it fits together

  • One backend, picked by a Cargo feature. backend-core (default) builds on better-duck-core; backend-diesel builds on better-duck-diesel (an r2d2 pool of DuckDbConnection + Diesel embed_migrations!). The webview command surface is identical either way — both engines implement the same DuckBackend trait, so your JS never changes. See Backends.
  • A fixed command set, not arbitrary RPC. Every command is a #[tauri::command] and is listed in build.rs so Tauri can generate its allow-* / deny-* permissions.
  • Two security layers: an init-time Rust Policy (mandatory) and declarative per-capability scope entries, both enforced before the backend touches DuckDB. See Security overview.

The command set at a glance

Every method on the JS Database class maps to exactly one Rust command (plugin:better-duck-tauri|<name>). Parameters bind as positional $1, $2, … from a values array.

30-second quickstart

Add the dependency (pick one backend feature) and register the plugin:
Grant permissions in a capability file (the default set is read-only; writes and raw SQL are opt-in):
Drive it from the frontend:
See Installation and Registration for the full setup.

See also

  • Installation — the Rust dependency, feature flags, and the JS package.
  • Registration — tauri::Builder wiring, simple and configured.
  • Security overview — the untrusted-webview threat model.
  • Feature flags — how backend-core, backend-diesel, and arrow relate to the rest of the workspace.