"A plugin isn't installed until it exists in three places. Two out of three is the silent-failure trap."
Three Surfaces, Every Time
Wiring a Tauri plugin correctly always touches three files. Hold this as a checklist:
- Cargo.toml — the Rust crate dependency (
tauri-plugin-store = "2"). - lib.rs — register it in the Builder chain (
.plugin(tauri_plugin_store::Builder::new().build())). - capabilities — grant its permission (
"store:default").
And usually a fourth, lighter one: the JS package (@tauri-apps/plugin-store) if you call it from the frontend. Miss the Cargo dep and it won't compile (loud, easy). Miss the builder and the plugin does nothing. Miss the capability and the frontend commands fail with a permission error. The two-of-three states fail quietly, which is why this rule is worth memorizing.
Removing Is Also Three Surfaces
The rule cuts both ways. When you remove a plugin, you must undo all three surfaces or you leave dead weight: an unused crate bloating your build, a builder line registering nothing useful, a capability granting a permission for a plugin that's gone. Cinder recorded exactly this as a learning — pulling a plugin meant editing the Cargo dependency, the lib.rs builder, and the capabilities file, in lockstep. Treat add and remove as symmetric three-surface operations.
Why This Design
It can feel like ceremony, but each surface serves the deny-by-default model: the Cargo dep brings the code, the builder activates it in the core, and the capability is the explicit grant that says 'yes, the frontend may use this.' The separation is what lets a plugin be present in your binary but unreachable from the webview until you opt in — security by construction, paid for with three edits.