tauri-v2
Skill16 starsChanged 7 months agoMITView on GitHub
Tauri v2+ cross-platform app development with Rust backend. Use when configuring tauri.conf.json, implementing Rust commands (#[tauri::command]), setting up IPC patterns (invoke, emit, channels), configuring permissions/capabilities, troubleshooting build issues, or deploying desktop/mobile apps. Triggers on Tauri, src-tauri, invoke, emit, capabilities.json.
17 other projects use a version of this, 8 of them edited.
Adopted by
Most recently taken up by
- mesomya/openusage-windowsedited, first seen Nov 8, 2026
- poweruserz/OpenTokenUsageedited, first seen Oct 15, 2026
- LikeNmuFF/deskmateeword for word, first seen Oct 11, 2026
- fjrevoredo/mini-diariumedited, first seen Oct 8, 2026
- codedogQBY/ReadAnyedited, first seen Oct 8, 2026
- pragma-sh/pragmaedited, first seen Oct 8, 2026
Used with
Projects with it also use tauri-development, shadcn and 3 more.
Other files people use alongside this one.
Files found in the same public projects as a version of this one, more often than they turn up anywhere else. Each project counts once, large collections count for less, and this file's own repository is left out.
poweruserzSkilltauri-development
Tauri development guidelines for building cross-platform desktop applications with TypeScript, Rust, and modern web technologies
Also in 3 projects that use this
DatabricksSkillshadcn
Manages shadcn components and projects — adding, searching, fixing, debugging, styling, and composing UI. Provides project context, component docs, and usage examples. Applies when working with shadcn/ui, component registries, presets, --preset codes, or any project with a components.json file. Also triggers for "shadcn init", "create an app with --preset", or "switch to --preset".
Also in 5 projects that use this
VercelSkillvercel-react-best-practices
React and Next.js performance optimization guidelines from Vercel Engineering. This skill should be used when writing, reviewing, or refactoring React/Next.js code to ensure optimal performance patterns. Triggers on tasks involving React components, Next.js pages, data fetching, bundle optimization, or performance improvements.
Also in 5 projects that use this
VercelSkillweb-design-guidelines
Review UI code for Web Interface Guidelines compliance. Use when asked to "review my UI", "check accessibility", "audit design", "review UX", or "check my site against best practices".
Also in 3 projects that use this
VercelSkillagent-browser
Automates browser interactions for web testing, form filling, screenshots, and data extraction. Use when the user needs to navigate websites, interact with web pages, fill forms, take screenshots, test web applications, or extract information from web pages.
Also in 3 projects that use this
Other versions17 projects use a version of this.
Word for word · 9
- pedronauck/skills★ 649100% same
- qlan-ro/mainframe★ 44100% same
- Bitslix/BLXCode★ 15100% same
- SoftwareSavants/verun★ 10100% same
- elaboration-studio/agentic-hub★ 4100% same
- LikeNmuFF/deskmatee★ 2100% same
- dbDev-code/w-skills★ 1100% same
- yidasanqian/skilldeck★ 1100% same
- AojdevStudio/development-kit★ 0100% same
Edited · 8
- codedogQBY/ReadAny★ 2.7k89% same
- fjrevoredo/mini-diarium★ 31889% same
- poweruserz/OpenTokenUsage★ 3789% same
- pragma-sh/pragma★ 25100% same
- mesomya/openusage-windows★ 889% same
- FelipeAngeli/skills★ 289% same
- gihwan-dev/claude-code-gui★ 189% same
- peakdong68/my-skills★ 089% same
Wrote their own version · 0
None found.
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository23 other files it gives its agents.
- AGENTS.mdAGENTS.md
- CLAUDE.mdCLAUDE.md
- cloudflare-vpc-servicesSkill
- code-reviewerSkill
- commit-helperSkill
- esphome-box3-builderSkill
- esphome-config-helperSkill
- frigate-configuratorSkill
- grafana-billingSkill
- grafana-plugin-scaffoldingSkill
- ha-addonSkill
- ha-apiSkill
- ha-automationSkill
- ha-dashboardSkill
- ha-energySkill
- ha-integrationSkill
- ha-voiceSkill
- kubernetes-healthSkill
- kubernetes-operationsSkill
- linearSkill
- typescript-v6Skill
- vitest-v4Skill
- vite-v8Skill
The file
Show its rules and text
We split this skill into the rules it gives an agent
20 rules. 6 are common, 1 is distinctive, and 13 are very specific to this project.
6
Common
Most of the 8 edited versions we read keep these.
1
Distinctive
This author's own choices. Worth a look.
13
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 70
Why this matters: Use @tauri-apps/api/core (not @tauri-apps/api/tauri - that's v1 API).
- Very specific: line 92
Use Mutex<T> for shared state accessed from multiple commands
- Common: line 93
Add capabilities before using any plugin features
- Very specific: line 94
Use lib.rs for shared code (required for mobile builds)
- Very specific: line 95
Use #[cfg_attr(mobile, tauri::mobile_entry_point)] on pub fn run() in lib.rs for mobile compatibility
- Very specific: line 99
Never use borrowed types (&str) in async commands - use owned types
- Common: line 100
Never block the main thread - use async for I/O operations
- Very specific: line 101
Never hardcode paths - use Tauri path APIs (app.path())
- Common: line 102
Never skip capability setup - even "safe" operations need permissions
- Very specific: line 237
Use Result<T, E> and thiserror for type-safe error propagation across the IPC boundary.
- Very specific: line 265
All command arguments must implement serde::Deserialize, and return types must implement serde::Serialize.
- Very specific: line 390
Why this matters: Use tauri::WebviewWindow and app.get_webview_window("label") in v2 — the v1 app.get_window() API is removed in v2.
- Very specific: line 444
Verify devUrl matches your frontend dev server port
- Very specific: line 445
Check beforeDevCommand runs your dev server
- Very specific: line 453
Verify command is in generate_handler![]
- Common: line 454
Check Rust command actually returns a value
- Common: line 455
Ensure argument names match (camelCase in JS, snake_case in Rust by default)
- Distinctive: line 472
Not all Tauri APIs and plugins support mobile (iOS/Android).
- Very specific: line 477
Conditional compilation: Use #[cfg(desktop)] / #[cfg(mobile)] for platform-specific Rust logic
- Common: line 491
Before using this skill, verify:
“Common” is measured: kept by at least 6 in 10 of the 8 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Tauri v2+ Development Skill
Build cross-platform desktop and mobile apps with web frontends and Rust backends.
Before You Start
This skill prevents 8+ common errors and saves ~60% tokens.
| Metric | Without Skill | With Skill |
| Setup Time | ~2 hours | ~30 min |
| Common Errors | 8+ | 0 |
| Token Usage | High (exploration) | Low (direct patterns) |
Known Issues This Skill Prevents
- Permission denied errors from missing capabilities
- IPC failures from unregistered commands in
generate_handler! - State management panics from type mismatches
- Mobile build failures from missing Rust targets
- White screen issues from misconfigured dev URLs
Quick Start
Step 1: Create a Tauri Command
// src-tauri/src/lib.rs
#[tauri::command]
fn greet(name: String) -> String {
format!("Hello, {}!", name)
}
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
tauri::Builder::default()
.invoke_handler(tauri::generate_handler![greet])
.run(tauri::generate_context!())
.expect("error while running tauri application");
}Why this matters: Commands not in generate_handler![] silently fail when invoked from frontend.
main.rsstays thin:src-tauri/src/main.rsshould only be a thin passthrough — all application logic lives inlib.rs:// src-tauri/src/main.rs #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] fn main() { app_lib::run(); }This split is required for mobile builds — Tauri replaces
main()withmobile_entry_pointon mobile targets.
Step 2: Call from Frontend
import { invoke } from '@tauri-apps/api/core';
const greeting = await invoke<string>('greet', { name: 'World' });
console.log(greeting); // "Hello, World!"Why this matters: Use @tauri-apps/api/core (not @tauri-apps/api/tauri - that's v1 API).
Step 3: Add Required Permissions
// src-tauri/capabilities/default.json
{
"$schema": "../gen/schemas/desktop-schema.json",
"identifier": "default",
"windows": ["main"],
"permissions": ["core:default"]
}Why this matters: Tauri v2 denies everything by default - explicit permissions required for all operations.
Critical Rules
Always Do
- Register every command in
tauri::generate_handler![cmd1, cmd2, ...] - Return
Result<T, E>from commands for proper error handling - Use
Mutex<T>for shared state accessed from multiple commands - Add capabilities before using any plugin features
- Use
lib.rsfor shared code (required for mobile builds) - Use
#[cfg_attr(mobile, tauri::mobile_entry_point)]onpub fn run()inlib.rsfor mobile compatibility
Never Do
- Never use borrowed types (
&str) in async commands - use owned types - Never block the main thread - use async for I/O operations
- Never hardcode paths - use Tauri path APIs (
app.path()) - Never skip capability setup - even "safe" operations need permissions
Common Mistakes
Wrong - Borrowed type in async:
#[tauri::command]
async fn bad(name: &str) -> String { // Compile error!
name.to_string()
}Correct - Owned type:
#[tauri::command]
async fn good(name: String) -> String {
name
}Why: Async commands cannot borrow data across await points; Tauri requires owned types for async command parameters.
Known Issues Prevention
| Issue | Root Cause | Solution |
| "Command not found" | Missing from generate_handler! | Add command to handler macro |
| "Permission denied" | Missing capability | Add to capabilities/default.json |
| Plugin feature silently fails | Plugin installed but permission not in capability | Add plugin permission string to capabilities/default.json |
| Updater fails in production | Unsigned artifacts or HTTP endpoint | Generate keys with cargo tauri signer generate, use HTTPS endpoint only |
| Sidecar not found | externalBin not in tauri.conf.json or missing executable | Add path to bundle.externalBin, ensure binary is bundled |
| Feature works on desktop, breaks on mobile | Desktop-only API used | Check if API has mobile support — some plugins are desktop-only |
| State panic on access | Type mismatch in State<T> | Use exact type from .manage() |
| White screen on launch | Frontend not building | Check beforeDevCommand in config |
| IPC timeout | Blocking async command | Remove blocking code or use spawn |
| Mobile build fails | Missing Rust targets | Run rustup target add <target> |
Deep-Dive References
- Security & permissions →
references/capabilities-reference.md - IPC decision guide →
references/ipc-patterns.md - Official plugins →
references/plugin-reference.md - Updater & distribution →
references/updater-distribution-reference.md - Tray, sidecars, deep links →
references/advanced-runtime-reference.md
Configuration Reference
tauri.conf.json
{
"$schema": "./gen/schemas/desktop-schema.json",
"productName": "my-app",
"version": "1.0.0",
"identifier": "com.example.myapp",
"build": {
"devUrl": "http://localhost:5173",
"frontendDist": "../dist",
"beforeDevCommand": "npm run dev",
"beforeBuildCommand": "npm run build"
},
"app": {
"windows": [{
"label": "main",
"title": "My App",
"width": 800,
"height": 600
}],
"security": {
"csp": "default-src 'self'; img-src 'self' data:",
"capabilities": ["default"]
}
},
"bundle": {
"active": true,
"targets": "all",
"icon": ["icons/icon.icns", "icons/icon.ico", "icons/icon.png"]
}
}Key settings:
build.devUrl: Must match your frontend dev server portapp.security.capabilities: Array of capability file identifiers
Plugin configuration — Some plugins require additional tauri.conf.json blocks (e.g., store, updater). Always check the specific plugin docs at v2.tauri.app/plugin/<plugin-name>/ for required config keys.
Project Structure
my-tauri-app/
├── src/ # Frontend source
├── src-tauri/
│ ├── src/
│ │ ├── main.rs # Thin passthrough — calls lib::run()
│ │ └── lib.rs # ALL application logic lives here
│ ├── capabilities/
│ │ └── default.json # Capability definitions (grant permissions here)
│ ├── tauri.conf.json # App configuration (devUrl, bundle, security)
│ ├── Cargo.toml # Rust dependencies
│ └── build.rs # Build script (required for tauri-build)
└── package.jsonWhy lib.rs owns all logic: Tauri replaces main() with #[cfg_attr(mobile, tauri::mobile_entry_point)] on mobile. All commands, state, and builder setup must live in lib.rs::run().
Cargo.toml
[package]
name = "app"
version = "0.1.0"
edition = "2021"
[lib]
name = "app_lib"
crate-type = ["staticlib", "cdylib", "rlib"]
[build-dependencies]
tauri-build = { version = "2", features = [] }
[dependencies]
tauri = { version = "2", features = [] }
serde = { version = "1", features = ["derive"] }
serde_json = "1"Key settings:
[lib]section: Required for mobile buildscrate-type: Must include all three types for cross-platform
Common Patterns
Error Handling Pattern
Use Result<T, E> and thiserror for type-safe error propagation across the IPC boundary. See references/ipc-patterns.md for full implementation details.
use thiserror::Error;
#[derive(Debug, Error)]
enum AppError {
#[error("IO error: {0}")]
Io(#[from] std::io::Error),
#[error("Not found: {0}")]
NotFound(String),
}
impl serde::Serialize for AppError {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: serde::ser::Serializer {
serializer.serialize_str(self.to_string().as_ref())
}
}
#[tauri::command]
fn risky_operation() -> Result<String, AppError> {
Ok("success".into())
}Serde Boundary Rules
All command arguments must implement serde::Deserialize, and return types must implement serde::Serialize. This is how Tauri bridges JSON over the IPC boundary.
use serde::{Deserialize, Serialize};
#[derive(Deserialize)]
struct CreateUserArgs {
name: String,
email: String,
role: Option<String>, // Optional fields use Option<T>
}
#[derive(Serialize)]
struct User {
id: u64,
name: String,
}
#[tauri::command]
fn create_user(args: CreateUserArgs) -> Result<User, String> {
Ok(User { id: 1, name: args.name })
}Common serde pitfalls:
- Field names are camelCase in JS, snake_case in Rust — Tauri automatically converts between them
Option<T>maps to optional JS arguments (can beundefinedornull)- Complex enums need
#[serde(tag = "type")]or similar to be JSON-safe - Error types must also implement
Serialize(see Error Handling Pattern above)
State Management Pattern
Tauri state manages application data across commands. See references/ipc-patterns.md for more complex state patterns.
use std::sync::Mutex;
use tauri::State;
struct AppState {
counter: u32,
}
#[tauri::command]
fn increment(state: State<'_, Mutex<AppState>>) -> u32 {
let mut s = state.lock().unwrap();
s.counter += 1;
s.counter
}
// In builder:
tauri::Builder::default()
.manage(Mutex::new(AppState { counter: 0 }))Event Emission Pattern
Events are fire-and-forget notifications. See references/ipc-patterns.md for bidirectional examples.
use tauri::Emitter;
#[tauri::command]
fn start_task(app: tauri::AppHandle) {
std::thread::spawn(move || {
app.emit("task-progress", 50).unwrap();
app.emit("task-complete", "done").unwrap();
});
}import { listen } from '@tauri-apps/api/event';
const unlisten = await listen('task-progress', (e) => {
console.log('Progress:', e.payload);
});
// Call unlisten() when doneChannel Streaming Pattern
Channels provide high-frequency, typed streaming from Rust to Frontend. See references/ipc-patterns.md for full implementation details.
use tauri::ipc::Channel;
#[derive(Clone, serde::Serialize)]
#[serde(tag = "event", content = "data")]
enum DownloadEvent {
Progress { percent: u32 },
Complete { path: String },
}
#[tauri::command]
async fn download(url: String, on_event: Channel<DownloadEvent>) {
for i in 0..=100 {
on_event.send(DownloadEvent::Progress { percent: i }).unwrap();
}
on_event.send(DownloadEvent::Complete { path: "/downloads/file".into() }).unwrap();
}import { invoke, Channel } from '@tauri-apps/api/core';
const channel = new Channel<DownloadEvent>();
channel.onmessage = (msg) => console.log(msg.event, msg.data);
await invoke('download', { url: 'https://...', onEvent: channel });Window Access Pattern
Tauri v2 uses WebviewWindow for unified window and webview management.
use tauri::Manager;
#[tauri::command]
fn focus_window(app: tauri::AppHandle) {
if let Some(window) = app.get_webview_window("main") {
let _ = window.set_focus();
}
}Why this matters: Use tauri::WebviewWindow and app.get_webview_window("label") in v2 — the v1 app.get_window() API is removed in v2.
Bundled Resources
References
Located in references/:
capabilities-reference.md- Permission patterns and examplesipc-patterns.md- Complete IPC examplesplugin-reference.md- Official plugin install, registration, and permission stringsupdater-distribution-reference.md- Signing, HTTPS requirements, and bundle shippingadvanced-runtime-reference.md-TrayIconBuilder, sidecars, deep links, and asset protocols
Note: For deep dives on specific topics, see the reference files above.
Dependencies
Required
| Package | Version | Purpose |
@tauri-apps/cli | ^2 (v2+) | CLI tooling |
@tauri-apps/api | ^2 (v2+) | Frontend APIs |
tauri | ^2 (v2+) | Rust core |
tauri-build | ^2 (v2+) | Build scripts |
*Last verified: 2026-04-02. Always check official changelog for feature timing.
Optional (Plugins)
| Package | Version | Purpose | Key Permission |
tauri-plugin-fs | ^2 (v2+) | File system access | fs:default |
tauri-plugin-dialog | ^2 (v2+) | Native dialogs | dialog:default |
tauri-plugin-shell | ^2 (v2+) | Shell commands, open URLs | shell:default |
tauri-plugin-http | ^2 (v2+) | HTTP client | http:default |
tauri-plugin-store | ^2 (v2+) | Key-value storage | store:default |
Plugin permissions are mandatory. Installing a plugin without adding its permission string to a capability file causes silent runtime failures. See
references/plugin-reference.mdfor full install + permission details for all official plugins.
Official Documentation
Troubleshooting
White Screen on Launch
Symptoms: App launches but shows blank white screen
Solution:
- Verify
devUrlmatches your frontend dev server port - Check
beforeDevCommandruns your dev server - Open DevTools (Cmd+Option+I / Ctrl+Shift+I) to check for errors
Command Returns Undefined
Symptoms: invoke() returns undefined instead of expected value
Solution:
- Verify command is in
generate_handler![] - Check Rust command actually returns a value
- Ensure argument names match (camelCase in JS, snake_case in Rust by default)
Mobile Build Failures
Symptoms: Android/iOS build fails with missing target
Solution:
# Android targets
rustup target add aarch64-linux-android armv7-linux-androideabi i686-linux-android x86_64-linux-android
# iOS targets (macOS only)
rustup target add aarch64-apple-ios x86_64-apple-ios aarch64-apple-ios-simDesktop vs Mobile Behavioral Differences
Not all Tauri APIs and plugins support mobile (iOS/Android). Before using any plugin or API in a mobile build:
- Check the plugin page at
v2.tauri.app/plugin/<name>/for platform support matrix - Common desktop-only items: System tray (
TrayIconBuilder), window labels/multi-window, some shell plugin features - Mobile-safe patterns: IPC commands/events/channels work on all platforms;
tauri::AppHandleis mobile-safe - Conditional compilation: Use
#[cfg(desktop)]/#[cfg(mobile)]for platform-specific Rust logic
#[tauri::command]
fn platform_info() -> String {
#[cfg(desktop)]
return "desktop".to_string();
#[cfg(mobile)]
return "mobile".to_string();
}Setup Checklist
Before using this skill, verify:
npx tauri infoshows correct Tauri v2 versionssrc-tauri/capabilities/default.jsonexists with at leastcore:default- All commands registered in
generate_handler![] lib.rscontains shared code (for mobile support)- Required Rust targets installed for target platforms
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

