Skip to main content
The plugin builds on exactly one backend, selected by a Cargo feature. Both expose the identical webview command API — the choice is purely about the Rust side (migrations, pooling, how connections are managed). Building with neither feature is a compile_error!.

The two backends

Both engines implement the DuckBackend trait; commands are written against the trait and dispatched through managed state, which is why your JS never changes when you switch.

The DuckBackend trait

Every command delegates to one trait method. The trait is the contract that keeps the two engines interchangeable:
Row is serde_json::Map<String, Value> (a JSON object); ExecuteResult is { rowsAffected }.

Connection-string resolution

Both engines resolve the webview’s connection string the same way: strip a leading duckdb: prefix, then map an empty string or :memory: to an in-memory database, otherwise treat it as a filesystem path.

How the engines differ

Dynamic SQL on the Diesel backend

The plugin forwards arbitrary statements plus JSON params, whose result shape is only known at runtime. Diesel’s compile-time QueryableByName cannot express that, so the Diesel engine runs dynamic-column SQL on the pooled connection’s underlying core Connection via inner_mut(), reusing the same DuckValue ⇄ JSON materialization as the core engine. The two backends therefore return byte-identical row shapes.

on_connect hook timing

The timing of on_connect hooks differs between backends:
  • Core: hooks run on every checked-out connection (each operation opens a short-lived connection).
  • Diesel: hooks are attached to the r2d2 manager and run once per physical connection — r2d2 reuses connections across checkouts, and re-registering a UDF on an already-initialized connection would fail.
Write hooks to be safe under their backend’s timing (idempotent registration, or rely on the once-per-connection diesel guarantee).

Choosing

  • Default to backend-core: a lighter dependency tree and the inline migration engine. This is what the example app uses.
  • Use backend-diesel when the app already uses better-duck-diesel (shared schema / DSL / embed_migrations!) and wants a connection pool.

See also

  • Checkpointing — WAL-flush strategies, identical across backends.
  • Migrations — the one place the two builders’ APIs differ.
  • Async & pooling — the pooling model the diesel backend builds on.