Choosing the Right Plugin

Learn how to evaluate, select, and integrate plugins in your Tauri v2 application, balancing community support, compatibility, and custom development needs.

Every Tauri application starts lean — core windowing, webview, and inter-process communication. Plugins add capabilities that aren’t bundled into the framework itself: file system access, persistent storage, HTTP clients, OAuth flows, and more. A poorly chosen plugin can introduce maintenance overhead, security gaps, or platform incompatibilities. A well-chosen one accelerates development and keeps the application easy to maintain.

This guide provides a decision framework for picking the right plugin when you work with Tauri v2 and a React + Vite frontend. It covers the landscape of plugin types, evaluation criteria, common mistakes, and a concrete walkthrough.

What Kinds of Plugins Exist in Tauri v2

Tauri v2 plugins come in four forms, and the choice between them depends on how much control you need and whether a solution already exists.

Official plugins are maintained by the Tauri core team. They follow a predictable naming convention: the Rust crate is tauri-plugin-<name>, and the JavaScript bindings live under @tauri-apps/plugin-<name>. Examples include the store, SQL, HTTP, and opener plugins. These are the safest starting point — they receive security patches, track Tauri v2 API changes, and come with documentation.

Community plugins are published by third-party developers, typically on crates.io and npm. Quality varies. Some are actively maintained and match the official standard; others are abandoned or target an older Tauri version.

Custom standalone plugins are Rust crates you build yourself, following the same structure as official ones (a Cargo crate and an optional NPM package for frontend bindings). This makes sense when you need a piece of functionality across multiple Tauri applications or you want to share it publicly.

Inline plugins are modules inside your own application code that use the plugin builder API but are registered directly in build.rs instead of living in a separate crate. They are not published to a registry. Inline plugins are useful for splitting a large application into logical domains while keeping everything in one repository — but they come with extra configuration overhead in v2.

Inline plugins are not a shortcut:

In Tauri v2, inline plugins still require a manifest registration through build.rs and proper permission declarations. They are not an escape hatch from the permission system. If you just need a few isolated commands, a plain Rust module invoked through #[tauri::command] is simpler.

When to Use an Existing Plugin

The strongest reason to pick an existing plugin is that someone else has already solved the problem, tested it across platforms, and dealt with edge cases you haven’t thought of yet. Start by checking the official plugin list on the Tauri website. If an official plugin covers your need, use it — unless it has a hard limitation that blocks your specific use case.

For community plugins, apply the evaluation criteria. A well-maintained community plugin can be as good as an official one, but you inherit the risk of it becoming unmaintained.

A sign that you should not use an existing plugin: it implements far more than you need and loads unnecessary code into your application. Tauri plugins add weight to the Rust binary and sometimes require additional frontend dependencies. If a plugin brings in a large dependency graph for one small function, the cost may not justify the benefit.

Official plugins are usually the right answer:

If you need file/URL opening, persistent key‑value storage, or SQLite, the official opener, store, and SQL plugins cover the vast majority of real‑world requirements. Starting with them saves weeks of development.

When to Create a Custom Plugin

Build a custom plugin when no existing plugin fits, or when the available options have significant maintenance or licensing problems. Custom plugins also become valuable when you want to enforce a consistent API across multiple projects — your own internal SDK packaged as a plugin. Why Create Plugins covers that decision in more depth.

A custom plugin gives you full control over the permission model, the Rust API, and the frontend bindings. The cost is that you own the testing, platform support, and ongoing compatibility with future Tauri releases. If the logic is simple and lives entirely inside one application, an inline plugin or plain commands are often a better fit than a standalone crate.

Don't extract a plugin too early:

Many developers create a separate plugin crate for logic that is only ever used by one application. This adds versioning overhead and build complexity without real benefit. Let the need for reuse guide the decision — if you aren't using it in at least two projects, keep it inside the app.

Evaluating a Plugin for Your Project

Not all plugins are safe to include. Before adding one to your Cargo.toml, walk through these checks.

Tauri Version Compatibility

The most common failure point is a plugin that targets Tauri v1 while your application uses v2. A v1 plugin crate will depend on the tauri crate with a 1.x version. Check the plugin's Cargo.toml:

[dependencies]
tauri = "2"
[dependencies]
tauri = "1"

If the plugin depends on tauri 1, it will not compile with a Tauri v2 application. For frontend bindings, the same rule applies: the NPM package for v2 lives under @tauri-apps/plugin-*, not the older unscoped tauri-plugin-* name.

Mixing Tauri v1 and v2 plugin dependencies breaks the build:

A v1 plugin crate pulled into a v2 project causes compile-time errors. If you install a v1 NPM package, the frontend calls will likely fail silently or throw cryptic runtime errors. Always verify the version before adding.

Platform Support

Some plugins work on desktop but not on mobile, or support Windows but not Linux. Check the plugin's documentation or its source code for platform-specific modules. Official plugins usually list platform support clearly. For community plugins, look at the repository's CI configuration — if it doesn't run tests on your target platforms, expect gaps.

Permission Model and Scoping

Every Tauri v2 plugin command requires explicit permission in the application's capability configuration. Good plugins document which permissions they expose and how to scope them. A plugin that exposes broad wildcard permissions without explaining how to restrict them might be difficult to lock down in a security-sensitive application.

A plugin with no documented permissions is a red flag:

If you cannot find a list of required permissions or example capability configurations, you will spend time reverse-engineering the security model. Prefer plugins that include a permissions directory with default permission sets and clear documentation.

Maintenance and Documentation

Check the plugin's GitHub repository for recent commits, open issues, and release frequency. A plugin last updated two years ago may have accumulated unpatched vulnerabilities or may be incompatible with the latest Tauri stable release. Look for a working example in the README — if you cannot get it running in 30 minutes, it is unlikely to get easier later.

A Decision Framework for Choosing

When you face a new feature requirement, run through these questions in order.

  1. Does an official Tauri plugin provide this exact capability? If yes, use it. You get security maintenance, platform support, and documentation without additional effort.
  2. Is there a well-maintained community plugin that covers the need? If yes, evaluate it against the criteria above. If it passes, use it — but monitor its repository for maintenance changes.
  3. Can the feature be implemented as a small set of Tauri commands without a plugin? For app-specific logic (e.g., calling a particular native API once), a few #[tauri::command] functions in the main Rust code are often simpler than a full plugin.
  4. Will this logic be reused across multiple applications? If yes, a custom plugin crate is justified. If no, an inline plugin or plain commands keep the codebase simpler.
  5. Does the logic require native mobile code (Kotlin/Swift)? A custom plugin with mobile project support may be necessary if the official mobile plugin APIs don't cover the use case.

This sequence prevents over-engineering while ensuring you don't accidentally adopt an unmaintained dependency.

Common Mistakes When Choosing Plugins

Installing a v1 Plugin in a v2 Application

The Tauri plugin ecosystem changed significantly between v1 and v2. The frontend package tauri-plugin-store is v1; the v2 equivalent is @tauri-apps/plugin-store. The Rust crate naming is similar but the internal APIs differ. Always look for the @tauri-apps scope on npm and the tauri dependency version in Cargo.toml.

Skipping Permission Configuration

After installing a plugin, frontend calls fail with an error like command not allowed or Plugin not found. This almost always means the plugin's permissions haven't been added to a capability file. Every command needs an explicit allow entry.

Not Registering Inline Plugin Manifests

If you create an inline plugin, Tauri v2 requires a build.rs registration that lists the plugin's commands. Without it, the plugin's manifest is unknown to the runtime and commands are blocked — even if you've added permissions.

fn main() {
    tauri_build::try_build(
        tauri_build::Attributes::new()
            .plugin(
                "my-inline-plugin",
                tauri_build::InlinedPlugin::new()
                    .commands(&["do_something", "do_something_else"]),
            ),
    )
    .expect("failed to run tauri-build");
}

Forgetting build.rs registration blocks all inline plugin commands:

The frontend will see Plugin did not define its manifest in the console, and invocations will silently fail. This is one of the most common support requests for custom plugins in Tauri v2.

Ignoring Platform Limitations

A plugin that works perfectly during development on macOS might fail on Windows or not compile for Android. Always test on all target platforms early in development, not right before shipping.

Using a Large Plugin for One Small Function

The official SQL plugin is excellent for database work, but pulling it in to store a single boolean flag is unnecessary — the store plugin or a simple JSON file would suffice. Match the plugin's scope to the problem.

Walkthrough: Selecting a Plugin for Opening Files and URLs

Imagine your React application needs to open external URLs in the default browser and reveal files in the system file explorer. You explore the options and find the official opener plugin.

First, you verify compatibility. The opener plugin’s Cargo.toml depends on tauri = "2", and its NPM package is @tauri-apps/plugin-opener. The documentation lists supported platforms and provides a clear permission table. This meets all the evaluation criteria.

You add the plugin to the project:

npm run tauri add opener

This command updates src-tauri/Cargo.toml with the tauri-plugin-opener crate and package.json with @tauri-apps/plugin-opener, then generates the initial capability configuration.

You then register the plugin in the Rust backend and configure permissions to allow opening https://tauri.app and revealing a specific directory.

#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
    tauri::Builder::default()
        .plugin(tauri_plugin_opener::init())
        .run(tauri::generate_context!())
        .expect("error while running tauri application");
}
{
  "$schema": "../gen/schemas/desktop-schema.json",
  "identifier": "main-capability",
  "description": "Capability for the main window",
  "windows": ["main"],
  "permissions": [
    {
      "identifier": "opener:allow-open-url",
      "allow": [{ "url": "https://tauri.app" }]
    },
    {
      "identifier": "opener:allow-reveal-item-in-dir",
      "allow": [{ "path": "$DOWNLOAD/*" }]
    }
  ]
}

Now the frontend can call the opener functions. In a React component, you might expose two buttons:

import { openUrl } from "@tauri-apps/plugin-opener";
export default function FileOpener() {
  const handleOpenWebsite = async () => {
    await openUrl("https://tauri.app");
  };
  return (
    <div>
      <button onClick={handleOpenWebsite}>Open Tauri Website</button>
    </div>
  );
}

The opener plugin is the right choice for these tasks:

Opening URLs and revealing files are exactly the problems the opener plugin was designed to solve. It is official, well‑maintained, and its permission scoping lets you lock down exactly which URLs and paths are accessible. No custom code needed.

This walkthrough mirrors the real decision process: identify a need, discover an official plugin, verify it against the evaluation criteria, and integrate it with explicit permissions.

Summary

Plugin selection in Tauri v2 is a balance between leveraging existing work and owning your dependencies. Official plugins are the lowest-risk option when they fit. Community plugins can fill gaps but require careful vetting — always check the Tauri version dependency, platform support, and maintenance activity. Custom plugins offer total control but shift the burden of upkeep onto you, and inline plugins are best reserved for in‑app organization rather than a substitute for standalone crates.

The single most impactful habit is to always verify the plugin’s Tauri version before adding it to your project. A v1 dependency pulled into a v2 codebase wastes hours on build errors that the version check would have prevented.