Tauri 2.x Plugin Ecosystem
SkillAI & modelsTauri 2.x official plugin ecosystem, plugin APIs, permissions, and custom plugin development
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the Tauri 2.x Plugin Ecosystem skill
What this skill tells your AI
The instructions your AI receives, as published by agents-inc/skills in src/skills/desktop-plugins-tauri/SKILL.md and read by ahel’s review.
Quick Guide: Tauri plugins follow a dual-install pattern: Cargo crate (Rust backend) + npm package (JS frontend). Every plugin must be registered with
.plugin()in Rust AND have permissions granted in a capability file. Missing any step causes runtime errors, not compile errors. Custom plugins usetauri::plugin::Builderwith optional mobile support (Swift/Kotlin). There are 30+ official plugins covering fs, http, dialog, store, notification, shell, updater, sql, log, stronghold, deep-link, global-shortcut, and more.Current version: Tauri 2.x (stable). All plugins require Rust 1.77.2+.
<critical_requirements>
CRITICAL: Before Using This Skill
All code must follow project conventions in CLAUDE.md (kebab-case, named exports, import ordering,
import type, named constants)
(You MUST complete ALL four installation steps for every plugin: 1) cargo add crate, 2) npm install bindings, 3) .plugin() registration in Rust, 4) permissions in capability file -- missing any step causes runtime errors)
(You MUST scope plugin permissions in capability files -- never grant unscoped fs:allow-read-text-file or http:default without URL restrictions)
(You MUST use @tauri-apps/plugin-* npm packages for JS bindings -- not @tauri-apps/api/* which is the core API)
(You MUST use #[cfg(desktop)] guard when registering desktop-only plugins -- mobile builds will fail otherwise)
(You MUST use tauri::plugin::Builder with an init() convention when creating custom plugins -- not raw command registration)
</critical_requirements>
Auto-detection: tauri-plugin, @tauri-apps/plugin, tauri_plugin, plugin registration, .plugin(), tauri-plugin-fs, tauri-plugin-http, tauri-plugin-store, tauri-plugin-dialog, tauri-plugin-notification, tauri-plugin-shell, tauri-plugin-updater, tauri-plugin-log, tauri-plugin-sql, tauri-plugin-stronghold, tauri-plugin-deep-link, tauri-plugin-global-shortcut, tauri-plugin-autostart, tauri-plugin-clipboard-manager, tauri-plugin-window-state, tauri-plugin-single-instance, tauri-plugin-barcode-scanner, tauri-plugin-biometric, tauri-plugin-os, tauri-plugin-process, custom plugin, plugin development, npx tauri plugin new
When to use:
- Installing and configuring official Tauri plugins
- Using plugin JavaScript APIs from the frontend
- Scoping plugin permissions in capability files
- Creating custom plugins with Rust backend + optional JS API
- Adding mobile support (Swift/Kotlin) to custom plugins
- Choosing between plugins for a specific use case (store vs stronghold, fs vs dialog)
When NOT to use:
- Tauri core framework patterns (commands, invoke, state, events, tray, windows -- use the framework skill)
- Frontend framework patterns (component architecture, state management -- use respective framework skills)
- General Rust programming not related to Tauri plugin APIs
- Build tool or bundler configuration (separate tooling concern)
Key patterns covered:
- Four-step plugin installation pattern (examples/core.md)
- Data & storage plugins: fs, store, sql, stronghold (examples/data-storage.md)
- System integration plugins: shell, notification, clipboard, dialog, os, process (examples/system.md)
- App lifecycle plugins: updater, deep-link, autostart, single-instance, window-state, global-shortcut (examples/lifecycle.md)
- Networking plugins: http, log, websocket, upload (examples/networking.md)
- Mobile-only plugins: barcode-scanner, biometric, geolocation, haptics, nfc (examples/mobile.md)
- Custom plugin development: Builder pattern, commands, config, lifecycle hooks, mobile support (examples/custom-plugins.md)
Detailed resources:
- examples/core.md - Installation pattern, permission scoping, multi-plugin registration
- examples/data-storage.md - fs, store, sql, stronghold plugin APIs
- examples/system.md - shell, notification, clipboard, dialog, os, process APIs
- examples/lifecycle.md - updater, deep-link, autostart, single-instance, window-state, global-shortcut
- examples/networking.md - http, log, websocket, upload
- examples/mobile.md - barcode-scanner, biometric, geolocation, haptics, nfc
- examples/custom-plugins.md - Custom plugin scaffolding, Builder, mobile (Swift/Kotlin)
- reference.md - Full plugin registry table, permission patterns, platform support matrix
Philosophy
Tauri plugins extend the core framework with native capabilities through a dual-architecture design: a Rust backend crate providing the implementation, and an npm package providing typed JavaScript bindings. This separation enforces security -- every plugin operation must be explicitly permitted in a capability file.
Plugin architecture principles:
- Security by default: Plugins do nothing until permissions are granted. Permissions are scoped per-window and can restrict operations to specific paths, URLs, or commands.
- Dual install: Rust crate handles native operations; npm package provides the typed JS API. Both are required.
- Platform awareness: Some plugins are desktop-only (shell, autostart, global-shortcut), some are mobile-only (barcode-scanner, biometric, haptics), and many work on both.
- Convention over configuration: All official plugins follow the same four-step install pattern. Custom plugins use
tauri::plugin::Builderwith aninit()export.
When to use plugins vs custom commands:
- Need file system, HTTP, notifications, or other OS features? Use the official plugin.
- Need custom business logic that runs in Rust? Write a Tauri command (framework skill).
- Need a reusable native capability shared across projects? Write a custom plugin.
When NOT to use a plugin:
- The JS Web API already covers the need (e.g.,
navigator.clipboardfor simple text copy in some contexts) - A custom Tauri command is simpler for a one-off operation
- The plugin is mobile-only but your app is desktop-only (or vice versa)
Core Patterns
Pattern 1: Four-Step Plugin Installation
Every official plugin requires exactly four steps. Missing any step causes runtime errors, not compile errors.
# Step 1: Add Rust crate
cargo add tauri-plugin-store
# Step 2: Add JS bindings
npm add @tauri-apps/plugin-store
# Step 3: Register plugin in Rust (src-tauri/src/lib.rs)
# .plugin(tauri_plugin_store::Builder::new().build())
# Step 4: Add permissions to capability file (src-tauri/capabilities/main.json)
# "store:default"
Why all four steps: Cargo crate = backend implementation, npm package = typed JS bindings, .plugin() = runtime activation, capability permission = frontend authorization. Any missing piece causes a runtime error with an unhelpful message.
Shortcut: cargo tauri add <plugin> handles steps 1 and 3 automatically. You still need npm install (step 2) and permissions (step 4).
See examples/core.md for multi-plugin registration and permission scoping.
Pattern 2: Permission Scoping
Plugins operate under least-privilege. Scope permissions to specific paths, URLs, or commands.
{
"permissions": [
"core:default",
{
"identifier": "fs:allow-read-text-file",
"allow": [{ "path": "$APPDATA/**" }]
},
{
"identifier": "http:default",
"allow": [{ "url": "https://api.example.com/**" }]
}
]
}
Why scoping matters: Unscoped fs:allow-read-text-file grants access to ANY file on the system. Unscoped http:default allows requests to ANY domain. Always restrict to the minimum required scope.
See examples/core.md for shell command scoping and window-specific permissions.
Pattern 3: Desktop-Only Plugin Guard
Desktop-only plugins (shell, autostart, global-shortcut, single-instance, window-state, positioner) must be wrapped in #[cfg(desktop)] to prevent mobile build failures.
tauri::Builder::default()
.setup(|app| {
#[cfg(desktop)]
{
app.handle().plugin(tauri_plugin_autostart::init(
tauri_plugin_autostart::MacosLauncher::LaunchAgent,
None,
));
app.handle().plugin(tauri_plugin_global_shortcut::Builder::new().build());
}
Ok(())
})
Key point: Without #[cfg(desktop)], the Rust compiler will fail on mobile targets because these crates do not support iOS/Android.
Pattern 4: Store vs Stronghold vs SQL
Three storage plugins serve different needs:
| Plugin | Use Case | Encryption | Query | Platform |
|---|---|---|---|---|
| Store | App preferences, settings | No | Key-value only | All |
| Stronghold | Secrets, API keys, tokens | Yes (Argon2) | Key-value only | Desktop |
| SQL | Structured data, relations | No (app-level) | Full SQL (SQLite/MySQL/Postgres) | All |
Decision: User preferences and simple config? Store. Sensitive credentials? Stronghold. Structured relational data? SQL.
See examples/data-storage.md for complete API examples for each.
Pattern 5: Updater with Signed Releases
The updater plugin requires cryptographic signatures -- this cannot be disabled. Updates check an endpoint, verify the signature, download, and install.
import { check } from "@tauri-apps/plugin-updater";
import { relaunch } from "@tauri-apps/plugin-process";
const update = await check();
if (update) {
await update.downloadAndInstall((event) => {
// event.event: "Started" | "Progress" | "Finished"
});
await relaunch();
}
Key point: Generate signing keys with cargo tauri signer generate. Set TAURI_SIGNING_PRIVATE_KEY during builds. The public key goes in tauri.conf.json. Losing the private key means you cannot ship updates to existing users.
See examples/lifecycle.md for endpoint JSON format and Rust API.
Pattern 6: Custom Plugin Development
Custom plugins use tauri::plugin::Builder with the init() convention.
use tauri::plugin::{Builder, TauriPlugin};
use tauri::Runtime;
#[tauri::command]
fn my_command() -> String {
"Hello from plugin".into()
}
pub fn init<R: Runtime>() -> TauriPlugin<R> {
Builder::new("my-plugin")
.invoke_handler(tauri::generate_handler![my_command])
.setup(|app, _api| {
// Initialize state, start background tasks
Ok(())
})
.build()
}
Key points: Plugin commands are invoked as plugin:my-plugin|my_command from JS. Scaffold a full plugin project with npx @tauri-apps/cli plugin new <name>. The template includes desktop.rs, mobile.rs, permissions, and JS bindings.
See examples/custom-plugins.md for lifecycle hooks, configuration, and mobile support.
<decision_framework>
Decision Framework
Plugin Selection
What native capability do you need?
|
+-- File system read/write?
| +-- tauri-plugin-fs (scoped to specific directories)
|
+-- File/folder picker dialog?
| +-- tauri-plugin-dialog (open, save, message, ask)
|
+-- HTTP requests bypassing CORS?
| +-- tauri-plugin-http (scope to specific domains)
|
+-- Persistent key-value storage?
| +-- Sensitive data (tokens, keys)? -> tauri-plugin-stronghold
| +-- App preferences/settings? -> tauri-plugin-store
|
+-- Relational/structured data?
| +-- tauri-plugin-sql (SQLite, MySQL, PostgreSQL)
|
+-- System notifications?
| +-- tauri-plugin-notification (check permissions first on macOS/mobile)
|
+-- Run external processes?
| +-- tauri-plugin-shell (desktop only, scope allowed commands)
|
+-- Auto-update?
| +-- tauri-plugin-updater (requires signed releases)
|
+-- Structured logging?
| +-- tauri-plugin-log (targets: stdout, file, webview)
|
+-- Custom URL scheme handling?
| +-- tauri-plugin-deep-link (configure per-platform)
|
+-- System-wide keyboard shortcuts?
| +-- tauri-plugin-global-shortcut (desktop only)
|
+-- Launch on system startup?
| +-- tauri-plugin-autostart (desktop only)
|
+-- Single app instance?
| +-- tauri-plugin-single-instance (desktop only)
|
+-- Remember window position/size?
| +-- tauri-plugin-window-state (desktop only)
|
+-- Clipboard access?
| +-- tauri-plugin-clipboard-manager
|
+-- Mobile camera/scanner?
| +-- tauri-plugin-barcode-scanner (mobile only)
|
+-- Biometric auth?
| +-- tauri-plugin-biometric (mobile only)
|
+-- OS/platform info?
| +-- tauri-plugin-os
|
+-- App restart/exit?
+-- tauri-plugin-process
Custom Plugin vs Custom Command
Is this a reusable capability shared across projects?
+-- YES -> Custom plugin (npx @tauri-apps/cli plugin new)
+-- NO -> Is it complex enough to need its own permission model?
+-- YES -> Custom plugin
+-- NO -> Regular Tauri command (simpler, framework skill)
</decision_framework>
<red_flags>
RED FLAGS
High Priority Issues:
- Missing any of the four installation steps (cargo, npm,
.plugin(), permissions) -- causes runtime error with unhelpful message - Unscoped filesystem permissions (
fs:allow-read-text-filewithout path restriction) -- grants access to entire filesystem - Unscoped HTTP permissions (
http:defaultwithout URL pattern) -- allows requests to any domain - Unscoped shell execute (
shell:allow-executewithout command allowlist) -- allows running arbitrary commands - Using
@tauri-apps/api/*imports for plugin functionality -- plugins use@tauri-apps/plugin-*packages - Registering desktop-only plugins without
#[cfg(desktop)]-- breaks mobile builds - Losing the updater signing private key -- makes shipping updates to existing users impossible
Medium Priority Issues:
- Using Store plugin for sensitive data (API keys, tokens) -- Store is NOT encrypted, use Stronghold
- Not checking
isPermissionGranted()before sending notifications on macOS/mobile - Granting
shell:allow-executewhen onlyshell:allow-open(URLs/files) is needed - Missing
sql:allow-executepermission (default only includes read operations) - Forgetting to call
stronghold.save()after modifications (changes are lost)
Common Mistakes:
- Installing the cargo crate but forgetting the npm package (or vice versa)
- Using
cargo tauri addand assuming all four steps are done (npm install and permissions still needed) - Not scoping HTTP plugin URLs -- allows the app to make requests to arbitrary servers
- Using the updater plugin on mobile (it is desktop-only)
- Expecting Store data to persist across app reinstalls (store location depends on app identifier)
Gotchas & Edge Cases:
- Plugin init variants: Some plugins use
.init()(fs, dialog, shell, notification), others useBuilder::new().build()(store, updater, global-shortcut, log) -- check each plugin's docs - Store autoSave: When
autoSave: false, you must callstore.save()manually. WhenautoSaveis a number, it debounces saves by that many milliseconds. - SQL default permissions: Only read operations (select, load, close) are granted by default --
sql:allow-executemust be added explicitly for INSERT/UPDATE/DELETE - Stronghold platform: Desktop-only. Store data as
Uint8Array(not strings) -- useTextEncoder/TextDecoderfor string conversion - Deep link desktop: On desktop, deep links arrive as command-line arguments. Combine with single-instance plugin to handle links when the app is already running.
- Global shortcut conflicts: Registering a shortcut already bound system-wide (e.g.,
Ctrl+C) silently fails or overrides the system binding depending on the OS - Window-state plugin: Automatically restores window position/size on startup with zero JS code needed -- just register the plugin
- Plugin registration order: Does not matter. Each
.plugin()call is independent.
</red_flags>
<critical_reminders>
CRITICAL REMINDERS
All code must follow project conventions in CLAUDE.md (kebab-case, named exports, import ordering,
import type, named constants)
(You MUST complete ALL four installation steps for every plugin: 1) cargo add crate, 2) npm install bindings, 3) .plugin() registration in Rust, 4) permissions in capability file -- missing any step causes runtime errors)
(You MUST scope plugin permissions in capability files -- never grant unscoped fs:allow-read-text-file or http:default without URL restrictions)
(You MUST use @tauri-apps/plugin-* npm packages for JS bindings -- not @tauri-apps/api/* which is the core API)
(You MUST use #[cfg(desktop)] guard when registering desktop-only plugins -- mobile builds will fail otherwise)
(You MUST use tauri::plugin::Builder with an init() convention when creating custom plugins -- not raw command registration)
Failure to follow these rules will cause silent runtime errors, security vulnerabilities from unscoped permissions, or broken mobile builds.
</critical_reminders>
Signals
- GitHub stars
- 24
- Forks
- 8
- Last commit
- Sep 2026
Advanced
- Catalog kind
- skill
- Gateway key
desktop-plugins-tauri- Source
- github.com/agents-inc/skills