Skip to main content
The frontend package @better-duck/tauri exposes a single default export — the Database class. Each method wraps one plugin command via invoke('plugin:better-duck-tauri|<command>', …), so the class is a typed, ergonomic front for the command set.

Lifecycle

A Database is a handle to one loaded connection. You obtain it with the static load, and release it with close.
  • Database.load(path) invokes load and returns a Database whose path is the connection string you passed. path is the identifier sent as db to every subsequent command.
  • db.close() invokes close, dropping the registered connection, and resolves to a boolean (whether one was open).
load is also where migrations run for a registered connection string, through the crash-safe backup protocol on disk. See Migrations.

Connection strings

The path you pass to Database.load is resolved on the Rust side by stripping a leading duckdb: prefix:
The connection string is the key the plugin stores the handle under, and the value a load scope entry and the allow_connection policy match against exactly. Keep it stable across the app, and match the exact string in your capability scope.

The method map

Every command takes db: this.path as its first argument automatically; you only pass the operation-specific arguments.

Error handling

The plugin’s Rust Error serializes to the webview as a plain string, so the invoke promise rejects with that string. There are four underlying kinds:

Value mapping

Parameters (JS → DuckDB)

values bind as positional $1, $2, …:

Results (DuckDB → JS)

Rows come back as JSON objects keyed by column name. Most types map directly; precision-sensitive ones are preserved as strings so they survive JS number limits:
Type the result row shape with the method generic: await db.select<{ id: number; name: string }>(…) returns { id, name }[].
For the full DuckDB type system you query through this plugin, see Queries & values.

See also