IPC
Compiler-derived Tauri commands, bindings, and typed events.
Tauri replaces Electron's preload bridge with a small, compiler-typed command
surface. The webview calls tauri.<domain>.<method>() (or useTauri()); Rust
owns privileged work. There is no Node API in the UI and no hand-written Zod IPC
schema. The capabilities ACL permits plugin APIs, while Rust types constrain the
custom commands.
The pipeline
#[tauri::command] and #[specta::specta] annotate a function in
src-tauri/src/commands/. collect_commands![] in src-tauri/src/lib.rs
registers it for both Tauri and tauri-specta. Specta generates the committed
src/lib/bindings.ts; the small wrappers in src/lib/tauri/ make that generated
surface pleasant to consume.
#[tauri::command]
#[specta::specta]
pub fn platform() -> String {
std::env::consts::OS.to_string()
}pnpm dev regenerates bindings in debug builds. The export_bindings Rust test
also regenerates them during cargo test, and CI fails if the committed result
drifts. Never edit bindings.ts directly.
Shipped command surface
There are 15 registered commands across seven frontend domains:
| Domain | Commands |
|---|---|
app | version, platform, open_external |
secure | get, set, delete |
logs | path, tail, openFolder |
window | showWindowSystemMenu |
diagnostics | get |
update | getStatus, check, download, install |
file | Dialog/File-plugin wrappers; no custom Rust command |
Use the domain API rather than invoke() directly:
import { tauri } from '@/lib/tauri'
const report = await tauri.diagnostics.get()
await tauri.app.openExternal('https://example.com')In React, useTauri('logs') returns the same typed singleton. The legacy
use-conveyor.ts remains because ported components still use it. It adapts real
Tauri modules, but setLocale() and windowSetTitlebarDark() are intentional
no-ops; new code should use tauri / useTauri.
Events
Rust-to-webview events use onTauriEvent() from src/lib/tauri/events.ts.
Its event map types single-instance, settings-changed, and update-status.
For example, a second launch focuses the current window in Rust and emits its
argv; the frontend parses that input through the navigation allow-list before it
navigates. The updater emits its typed status after each transition.
Add a command
collect_commands![]; the builder already feeds invoke_handler.pnpm dev or cargo test --manifest-path src-tauri/Cargo.toml, then commit the generated bindings.src/lib/tauri/ domain.Result/rejected promise in the UI.An ungranted plugin call is denied by Tauri before the implementation runs. Do not solve that by adding a wildcard: identify the required permission and scope it in Capabilities.
