🎯

tauri-v2

🎯Skill

from nodnarbnitram/claude-code-extensions

VibeIndex|
What it does

tauri-v2 skill from nodnarbnitram/claude-code-extensions

πŸ“¦

Part of

nodnarbnitram/claude-code-extensions(19 items)

tauri-v2

Installation

npxRun with npx
npx tauri info
πŸ“– Extracted from docs: nodnarbnitram/claude-code-extensions
143Installs
3
-
Last UpdatedJan 15, 2026

Skill Details

SKILL.md

"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."

Overview

# 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

  1. Permission denied errors from missing capabilities
  2. IPC failures from unregistered commands in generate_handler!
  3. State management panics from type mismatches
  4. Mobile build failures from missing Rust targets
  5. White screen issues from misconfigured dev URLs

Quick Start

Step 1: Create a Tauri Command

```rust

// src-tauri/src/lib.rs

#[tauri::command]

fn greet(name: String) -> String {

format!("Hello, {}!", name)

}

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.

Step 2: Call from Frontend

```typescript

import { invoke } from '@tauri-apps/api/core';

const greeting = await invoke('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

```json

// 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 from commands for proper error handling
  • Use Mutex for shared state accessed from multiple commands
  • Add capabilities before using any plugin features
  • Use lib.rs for shared code (required for mobile builds)

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:

```rust

#[tauri::command]

async fn bad(name: &str) -> String { // Compile error!

name.to_string()

}

```

Correct - Owned type:

```rust

#[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 |

| State panic on access | Type mismatch in State | 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 |

Configuration Reference

tauri.conf.json

```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 port
  • app.security.capabilities: Array of capability file identifiers

Cargo.toml

```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 builds
  • crate-type: Must include all three types for cross-platform

Common Patterns

Error Handling Pattern

```rust

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(&self, serializer: S) -> Result

where S: serde::ser::Serializer {

serializer.serialize_str(self.to_string().as_ref())

}

}

#[tauri::command]

fn risky_operation() -> Result {

Ok("success".into())

}

```

State Management Pattern

```rust

use std::sync::Mutex;

use tauri::State;

struct AppState {

counter: u32,

}

#[tauri::command]

fn increment(state: State<'_, Mutex>) -> 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

```rust

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();

});

}

```

```typescript

import { listen } from '@tauri-apps/api/event';

const unlisten = await listen('task-progress', (e) => {

console.log('Progress:', e.payload);

});

// Call unlisten() when done

```

Channel Streaming Pattern

```rust

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) {

for i in 0..=100 {

on_event.send(DownloadEvent::Progress { percent: i }).unwrap();

}

on_event.send(DownloadEvent::Complete { path: "/downloads/file".into() }).unwrap();

}

```

```typescript

import { invoke, Channel } from '@tauri-apps/api/core';

const channel = new Channel();

channel.onmessage = (msg) => console.log(msg.event, msg.data);

await invoke('download', { url: 'https://...', onEvent: channel });

```

Bundled Resources

References

Located in references/:

  • [capabilities-reference.md](references/capabilities-reference.md) - Permission patterns and examples
  • [ipc-patterns.md](references/ipc-patterns.md) - Complete IPC examples

> Note: For deep dives on specific topics, see the reference files above.

Dependencies

Required

| Package | Version | Purpose |

|---------|---------|---------|

| @tauri-apps/cli | ^2.0.0 | CLI tooling |

| @tauri-apps/api | ^2.0.0 | Frontend APIs |

| tauri | ^2.0.0 | Rust core |

| tauri-build | ^2.0.0 | Build scripts |

Optional (Plugins)

| Package | Version | Purpose |

|---------|---------|---------|

| tauri-plugin-fs | ^2.0.0 | File system access |

| tauri-plugin-dialog | ^2.0.0 | Native dialogs |

| tauri-plugin-shell | ^2.0.0 | Shell commands, open URLs |

| tauri-plugin-http | ^2.0.0 | HTTP client |

| tauri-plugin-store | ^2.0.0 | Key-value storage |

Official Documentation

  • [Tauri v2 Documentation](https://v2.tauri.app/)
  • [Commands Reference](https://v2.tauri.app/develop/calling-rust/)
  • [Capabilities & Permissions](https://v2.tauri.app/security/capabilities/)
  • [Configuration Reference](https://v2.tauri.app/reference/config/)

Troubleshooting

White Screen on Launch

Symptoms: App launches but shows blank white screen

Solution:

  1. Verify devUrl matches your frontend dev server port
  2. Check beforeDevCommand runs your dev server
  3. Open DevTools (Cmd+Option+I / Ctrl+Shift+I) to check for errors

Command Returns Undefined

Symptoms: invoke() returns undefined instead of expected value

Solution:

  1. Verify command is in generate_handler![]
  2. Check Rust command actually returns a value
  3. 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:

```bash

# 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-sim

```

Setup Checklist

Before using this skill, verify:

  • [ ] npx tauri info shows correct Tauri v2 versions
  • [ ] src-tauri/capabilities/default.json exists with at least core:default
  • [ ] All commands registered in generate_handler![]
  • [ ] lib.rs contains shared code (for mobile support)
  • [ ] Required Rust targets installed for target platforms