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
Databasehandle and calls typed methods thatinvokeplugin 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 throughbetter-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 onbetter-duck-core;backend-dieselbuilds onbetter-duck-diesel(an r2d2 pool ofDuckDbConnection+ Dieselembed_migrations!). The webview command surface is identical either way — both engines implement the sameDuckBackendtrait, so your JS never changes. See Backends. - A fixed command set, not arbitrary RPC. Every command is a
#[tauri::command]and is listed inbuild.rsso Tauri can generate itsallow-*/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 JSDatabase 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:See also
- Installation — the Rust dependency, feature flags, and the JS package.
- Registration —
tauri::Builderwiring, simple and configured. - Security overview — the untrusted-webview threat model.
- Feature flags — how
backend-core,backend-diesel, andarrowrelate to the rest of the workspace.