Tauri Plugin System: Architecture, Official Plugins, and Implementation Guide
The Tauri plugin system is a Rust-based extension framework that enables developers to add native functionality to Tauri applications through reusable crates exposing both backend commands and JavaScript APIs via the tauri::plugin::Builder pattern.
The Tauri plugin system provides the primary extension mechanism for the tauri-apps/tauri ecosystem, allowing developers to encapsulate platform-specific features into modular components. Each plugin consists of a Rust crate that registers invoke handlers and lifecycle callbacks with the core runtime, paired with TypeScript bindings that expose type-safe methods to the frontend webview. This architecture maintains strict separation between native capabilities and web content while enabling secure, asynchronous communication across the IPC boundary.
Core Architecture and Builder Pattern
At the heart of the Tauri plugin system lies the tauri::plugin::Builder struct defined in crates/tauri/src/plugin.rs. This builder implements a fluent API for constructing TauriPlugin<R> instances that attach to the application runtime at compile time.
The builder registers five key components:
- Setup hooks – Optional initialization code executed when the application starts
- Invoke handlers – Command receivers that process requests from the JavaScript frontend via
invoke - JavaScript init scripts – Code injected into the webview before page load
- Custom URI scheme protocols – Handlers for specialized resource loading
- Lifecycle callbacks – Hooks such as
on_page_loadoron_window_readyfor responding to application state changes
The final build() method produces a TauriPlugin<R> that integrates with tauri::Builder through the .plugin() method.
Plugin Registration and Initialization
Integrating a plugin requires calling its initialization function within the Tauri application builder. According to the source code in crates/tauri/src/plugin.rs, every plugin exposes an init() function returning TauriPlugin<R>.
// src-tauri/src/main.rs
fn main() {
tauri::Builder::default()
.plugin(my_plugin::init())
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
The my_plugin::init() entry point constructs the plugin using the builder pattern, configuring all handlers and scripts before returning the typed plugin instance. This registration occurs at compile time, ensuring type safety across the Rust-JavaScript boundary.
Implementing Custom Plugins
Minimal Plugin Definition
Creating a plugin starts with defining a Rust crate that uses PluginBuilder to register commands. The following example from the plugin architecture demonstrates the essential structure:
// my_plugin/src/lib.rs
use tauri::{
plugin::{Builder as PluginBuilder, TauriPlugin},
Runtime,
generate_handler,
};
#[tauri::command]
async fn greet(name: String) -> String {
format!("Hello, {name}!")
}
pub fn init<R: Runtime>() -> TauriPlugin<R> {
PluginBuilder::new("my_plugin")
.invoke_handler(generate_handler![greet])
.js_init_script(r#"
window.__my_plugin = {
greet: (name) => window.__TAURI_INVOKE__('my_plugin:greet', { name })
};
"#)
.build()
}
The generate_handler! macro creates the dispatch logic for the greet command, while js_init_script injects frontend helpers into the webview context.
TypeScript Frontend Integration
After adding the plugin via tauri plugin add my_plugin, the CLI generates TypeScript bindings in the @tauri-apps/plugin-my-plugin-api package:
import { greet } from '@tauri-apps/plugin-my-plugin-api';
async function sayHello() {
const reply = await greet('World');
console.log(reply); // → "Hello, World!"
}
The generated API wraps the underlying invoke calls, providing IntelliSense and compile-time type checking for plugin commands.
CLI Scaffolding and Plugin Templates
The Tauri CLI provides automated scaffolding for new plugins through the tauri plugin new command. This generator creates the complete project structure found in crates/tauri-cli/templates/plugin/, including:
- Cargo.toml with proper dependencies and metadata
- TypeScript binding definitions
- Android and iOS project stubs for mobile support
- Default permission configurations
The template implements the standard builder skeleton, allowing developers to focus on business logic rather than boilerplate. For existing projects, tauri plugin init adds the necessary configuration to consume external plugins, as implemented in crates/tauri-cli/src/plugin/init.rs.
Permission Model and Security
Each plugin declares its required capabilities through a default permission set (e.g., core:default). The Tauri ACL (Access Control List) system, integrated into the plugin template, automatically grants these permissions when the plugin is registered. This model ensures that native capabilities remain explicitly opt-in, with granular control over which commands and resources each plugin can access.
Official Tauri Plugins
The tauri-apps organization maintains several first-party plugins that demonstrate the system's capabilities. These plugins follow the standardized builder pattern and reside in dedicated repositories:
- SQL Plugin – Provides encrypted SQLite database access for desktop and mobile applications via
tauri-plugin-sql - Stronghold Plugin – Implements secure cryptographic storage using the IOTA Stronghold library through
tauri-plugin-stronghold - Authenticator Plugin – Enables biometric authentication including Face ID, Touch ID, and Windows Hello support via
tauri-plugin-authenticator
These official plugins are referenced in the architecture documentation (ARCHITECTURE.md) and can be added to any Tauri project using tauri plugin add <name>.
Summary
- The Tauri plugin system uses
tauri::plugin::Builderincrates/tauri/src/plugin.rsto construct native extensions with invoke handlers, lifecycle hooks, and JavaScript initialization scripts. - Plugins register with the application through an
init()function called withintauri::Builder, enabling compile-time integration of native capabilities. - The CLI scaffolding tools in
crates/tauri-cli/templates/plugin/generate complete plugin projects including Rust crates, TypeScript bindings, and mobile platform stubs. - Official plugins such as SQL, Stronghold, and Authenticator provide production-ready implementations of common native features while adhering to the system's security and permission models.
Frequently Asked Questions
How do I create a new Tauri plugin from scratch?
Use the CLI command tauri plugin new <name> to generate a complete scaffold including the Rust crate structure, TypeScript API definitions, and optional Android/iOS projects. This creates the standard builder pattern implementation in src/lib.rs with hooks for setup, invoke handlers, and JavaScript initialization scripts.
What is the difference between a Tauri plugin and a Tauri command?
A Tauri command is a single function exposed to JavaScript via invoke, while a Tauri plugin is a complete crate bundling multiple commands, lifecycle hooks, initialization scripts, and platform-specific code. Plugins provide modular distribution through Cargo and NPM, whereas commands are typically defined inline within the application code.
Where are official Tauri plugins maintained?
Official plugins including SQL, Stronghold, and Authenticator reside in separate repositories under the tauri-apps organization, distinct from the core tauri-apps/tauri repository. Each plugin follows the standardized builder pattern and publishes to crates.io and the NPM registry under the @tauri-apps scope.
How does the Tauri plugin system handle security permissions?
Each plugin declares a default permission set in its configuration, which the Tauri ACL system automatically applies when the plugin is registered. This declarative model ensures that native capabilities remain explicitly scoped, requiring developers to grant specific permissions for filesystem access, network requests, or hardware features within their capabilities configuration.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →