What are Plugins?
Learn what plugins are in Tauri v2, why they exist, how they differ from built-in APIs, and how they extend your React application with native functionality.
A Tauri app starts with a Rust-powered core that manages windows, exposes a web view, and handles a handful of essential system interactions. But a real application needs to read files from disk, talk to an SQLite database, send HTTP requests, or open a URL in the default browser. The Tauri core does not ship with every conceivable feature built in. Instead, it provides a mechanism to bolt on exactly the native capabilities your project needs. That mechanism is called a plugin.
A plugin is a separate Rust crate — often paired with a JavaScript package — that extends a Tauri application with new commands, events, or lifecycle hooks. If you have ever installed a browser extension or a VS Code plugin, the mental model is similar: the host app supplies a defined interface, and the plugin adds focused functionality without forcing the host to carry everything by default.
Tauri v2 only:
Plugins in Tauri v2 work differently from v1. The permission model, naming conventions, and initialization steps have changed. Everything in this document applies to Tauri v2 exclusively.
Why Plugins Exist
Tauri’s core crate is deliberately minimal. It contains the windowing system, web view glue, the inter-process communication (IPC) bridge, and a few foundational APIs — not much more. This keeps the binary small, the compile times reasonable, and the attack surface narrow.
The trade‑off is obvious: most applications need more than the bare minimum. Plugins solve that by letting each project pull in exactly the features it actually uses. If your app never touches the file system, you never even include the file system plugin. If you need full‑text search, someone can publish a plugin and you add it with two package managers.
The Tauri team sums this up directly:
“By design, the Tauri core does not contain features not needed by everyone. Instead it offers a mechanism to add external functionalities into a Tauri application called plugins.”
This opt‑in design is not just about disk space. It also means that each plugin can evolve independently of the Tauri core. A SQL plugin can release a patch without waiting for a new version of the entire framework.
Built‑in APIs vs Plugins
Tauri ships with a handful of APIs that live inside the core crate. These are the capabilities that the framework considers fundamental for nearly every desktop or mobile window: managing windows, reading resource files, handling the menu and tray, listening to system events, and a few others.
Plugins exist for everything else — including things that were part of the core in Tauri v1, like shell access, file dialog, and updater. The table below illustrates the split.
| Included in Core (always present) | Available via Plugins (opt‑in) |
|---|---|
| Window management | Persistent key‑value storage (Store) |
| App metadata & lifecycle | SQLite database queries (SQL) |
| Menu and tray | HTTP client (HTTP) |
| Resource file serving | Spawning child processes (Process) |
| Event system | Checking for application updates (Updater) |
| Path utilities | OAuth authentication flows (OAuth) |
| Deep link handling (Deep Link) | |
| Opening files/URLs with the system default (Opener) |
Core APIs still need permissions:
Even built‑in APIs are locked behind Tauri’s capability system. Your frontend code cannot call them unless you grant the appropriate permission. Plugins add yet another layer: they need both the capability entries for their commands and the plugin crate itself to be initialized in Rust.
The distinction matters because you will see both "window:allow-set-title" (a core API permission) and "store:allow-set" (a plugin command permission) in your capability files. They look similar in configuration, but the source of the command is different. Core APIs are always linked; plugin commands exist only after you add the crate and initialize it.
Official Plugins
The Tauri project maintains a set of plugins under the tauri-apps GitHub organization. These follow a common naming convention: the Rust crate is tauri-plugin-<name> and the JavaScript package is @tauri-apps/plugin-<name>.
Examples of official plugins include:
- Store – simple key‑value persistence backed by a file on disk
- SQL – full SQLite database support with migrations
- HTTP – an HTTP client that bypasses the browser’s networking limits
- Process – spawn and manage subprocesses from the backend
- Updater – built‑in application update checking and downloading
- OAuth – authentication flows that need native redirect handling
- Deep Link – handle custom URI schemes like
myapp:// - Opener – open files and URLs with the operating system’s default application
When you need a capability that fits one of these descriptions, reach for the official plugin first. It is tested against the same Tauri version, follows the security and permission patterns correctly, and receives updates alongside the core framework.
Official plugins are verified:
Official plugins are the safest starting point. They are audited by the Tauri maintainers and come with pre‑defined permission sets that you can simply reference in your capability configuration.
Community Plugins
Beyond the official set, the broader Rust and Tauri ecosystem contains community‑maintained plugins. They live on crates.io and npm just like any other library, usually with the tauri-plugin- prefix but without the official GitHub organization stamp.
A few things to keep in mind with community plugins:
- Check that the plugin’s version supports your exact Tauri version. A mismatch can cause compilation failures or subtle runtime errors.
- Read the plugin’s permission documentation. A community plugin might require you to write custom permission entries.
- Prefer plugins that have recent commits, an open issues history that gets responses, and clear usage instructions.
Unmaintained plugins are risky:
A plugin that has not been updated since Tauri v1 will not work in a v2 project. The permission and command registration internals changed significantly. Always verify that a community plugin explicitly states v2 support before adding it.
For the rest of this chapter, we will focus on the official plugins because they form the backbone of most Tauri v2 applications. Everything you learn about their structure and usage transfers directly to a well‑built community plugin.
A Concrete Example: Opening a URL from Your React Frontend
The opener plugin is one of the simplest official plugins. It exposes a single JavaScript function that tells the operating system to open a URL or a file with the default application. This is a perfect example of what a plugin does: it gives your React code access to a native operating system capability that a plain browser would not allow.
1. Add the Rust crate
Run this command in your project’s src-tauri directory:
cargo add tauri-plugin-opener
This adds tauri-plugin-opener to your Cargo.toml and downloads the source.
2. Initialize the plugin in your Tauri builder
Open src-tauri/src/lib.rs and register the plugin. In a typical Tauri v2 project the file already contains a run function that builds the app.
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
tauri::Builder::default()
.plugin(tauri_plugin_opener::init()) // new line
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
The .plugin(...) call wires the opener’s commands and lifecycle hooks into your app. Without it, the Rust side knows nothing about the plugin, and any JavaScript call will fail.
3. Install the JavaScript bindings
From the project root (not src-tauri), install the corresponding NPM package:
npm install @tauri-apps/plugin-opener
The package wraps the Rust commands into TypeScript functions that you can import in your React components.
4. Call the plugin from a React component
Now you can open a URL directly from your frontend code. Here is a minimal React button that does exactly that.
import { openUrl } from "@tauri-apps/plugin-opener";
function App() {
const handleOpen = async () => {
await openUrl("https://v2.tauri.app");
};
return (
<div>
<h1>My Tauri App</h1>
<button onClick={handleOpen}>Open Tauri Docs</button>
</div>
);
}
export default App;
When the user clicks the button, openUrl sends a command to the Rust backend, which hands the URL to the operating system’s default browser. No <a> tag, no window.open — the request travels through the Tauri IPC bridge, reaches the plugin’s Rust handler, and the OS takes over.
You must still grant permission:
The code above will not work until you add the appropriate permission in your capability file. Without it, Tauri blocks the command silently and you will see no visible error in the UI.
Plugins and Security Permissions
Tauri v2 introduced a capability‑based permission system that applies to every command, whether it comes from a core API or a plugin. A plugin cannot execute its commands until you explicitly allow them in a capability file.
For the opener plugin, you need to allow the open-url command and specify which URLs are permitted. Create or edit src-tauri/capabilities/default.json:
{
"$schema": "../gen/schemas/desktop-schema.json",
"identifier": "main-capability",
"description": "Capability for the main window",
"windows": ["main"],
"permissions": [
"core:default",
"opener:allow-open-url",
{
"identifier": "opener:allow-open-url",
"allow": [
{ "url": "https://v2.tauri.app" }
]
}
]
}
The "opener:allow-open-url" entry enables the command, and the scoped allow block restricts it to exactly the URL you intend to open. After this change, rebuild the app — the button will now work.
This pattern repeats for every plugin: install the crate, register it in lib.rs, install the JavaScript package, and then declare the required permissions in a capability file.
Summary
Tauri plugins are the mechanism that turns a minimal web‑view‑and‑window shell into a full‑fledged desktop application. They exist because the core cannot (and should not) bundle every possible feature. The Tauri project maintains a curated set of official plugins that cover storage, networking, database access, and many other common needs. Community plugins extend the ecosystem further, though you must verify v2 compatibility.
A plugin is not a magical auto‑configured add‑on. It requires three distinct steps on your side: adding the Rust crate, registering it in the Tauri builder, and declaring permissions. The JavaScript package is the bridge that lets your React components call the plugin’s commands with plain function invocations.