rust-tauri-development
Rust Tauri Development
Expert Tauri v2 development for building desktop applications with Rust backend and web frontend.
DECISION POINTS
IPC Pattern Selection
Data Exchange Pattern:
├─ Request/Response needed?
│ ├─ YES: Use #[tauri::command]
│ │ ├─ Sync operation? → fn command() -> Result<T, String>
│ │ └─ I/O operation? → async fn command() -> Result<T, String>
│ └─ NO: Fire-and-forget?
│ ├─ YES: Use events (emit/listen)
│ └─ Large binary data? → Use raw payload channels
State Management Pattern:
├─ Simple shared data?
│ ├─ Read-only → Arc<T>
│ ├─ Mutable + sync access → Arc<Mutex<T>>
│ └─ Mutable + async access → Arc<RwLock<T>>
├─ Database needed?
│ ├─ Simple KV → tauri-plugin-store
│ └─ Relational → tauri-plugin-sql
└─ Cross-process state? → Database or file-based
Window Architecture
Window Count Decision:
├─ Single window app?
│ └─ Use default main window only
├─ Settings/preferences needed?
│ └─ Create secondary window with restricted capabilities
├─ Background processing?
│ ├─ System tray → TrayIconBuilder + hidden main window
│ └─ No tray → Keep main window, emit progress events
└─ Multi-document interface?
└─ Create window per document with shared state
Plugin vs Custom Code
Functionality needed:
├─ File system access?
│ ├─ Basic read/write → cargo tauri add fs
│ └─ Complex file ops → Custom commands + std::fs
├─ HTTP requests?
│ ├─ Simple → reqwest in custom commands
│ └─ Complex proxy/auth → Custom plugin
├─ Database?
│ ├─ SQLite/MySQL → cargo tauri add sql
│ └─ Custom storage → Custom plugin
└─ Platform integration?
├─ Notifications → cargo tauri add notification
└─ Custom system APIs → Custom plugin
FAILURE MODES
Thread Blocking Anti-Pattern
Detection Rule: If UI freezes during Rust command execution Symptoms:
- Frontend becomes unresponsive
- Spinning cursor on macOS/Windows
- DevTools shows pending invoke() calls Fix: Convert blocking command to async or spawn onto background thread
// BAD: Blocks the main thread
#[tauri::command]
fn heavy_computation() -> String {
std::thread::sleep(Duration::from_secs(5)); // UI freezes
"done".to_string()
}
// GOOD: Async command
#[tauri::command]
async fn heavy_computation() -> String {
tokio::time::sleep(Duration::from_secs(5)).await;
"done".to_string()
}
Serialization Panic Trap
Detection Rule: If app crashes with "failed to serialize" during invoke() Symptoms:
- App crash on specific command calls
- Serde errors in console
- Commands work with simple data but fail with complex types Fix: Ensure all command parameters/returns implement Serialize/Deserialize
// BAD: Missing derives
struct MyData {
field: String,
}
// GOOD: Proper derives
#[derive(Serialize, Deserialize)]
struct MyData {
field: String,
}
Permission Escalation Error
Detection Rule: If commands fail with "not allowed" or capability errors Symptoms:
- Plugin commands return permission denied
- File operations fail unexpectedly
- "capability not granted" in logs Fix: Add required permissions to capabilities/*.json
{
"permissions": [
"fs:allow-read",
"fs:scope-app-data" // Add specific scopes
]
}
State Race Condition Bug
Detection Rule: If shared state shows inconsistent values between windows Symptoms:
- Data corruption in multi-window apps
- Commands occasionally return stale data
- State updates lost intermittently Fix: Use proper async locking (RwLock for async, Mutex for sync)
// BAD: No synchronization
static mut COUNTER: i32 = 0;
// GOOD: Proper state management
struct AppState {
counter: Arc<Mutex<i32>>,
}
WebView Platform Divergence
Detection Rule: If layout/behavior differs dramatically between macOS and Windows Symptoms:
- CSS renders differently on different platforms
- JavaScript APIs work on one platform but not others
- Font rendering inconsistencies Fix: Test on all platforms, use cross-platform CSS, avoid WebKit-specific features
WORKED EXAMPLES
Building a File Manager App
Scenario: Create a desktop file manager with folder tree, file operations, and progress tracking.
Step 1: Architecture Decision
- Need file system access → Use tauri-plugin-fs
- Progress updates → Use events for real-time feedback
- Multi-pane UI → Single window with multiple views
Step 2: Setup Capabilities
{
"permissions": [
"core:default",
"fs:allow-read",
"fs:allow-write",
"fs:allow-create",
"fs:scope-downloads",
"fs:scope-documents"
]
}
Step 3: Implement Backend Commands
#[tauri::command]
async fn list_directory(path: String, app: AppHandle) -> Result<Vec<FileEntry>, String> {
let entries = std::fs::read_dir(&path)
.map_err(|e| e.to_string())?
.collect::<Result<Vec<_>, _>>()
.map_err(|e| e.to_string())?;
let mut files = Vec::new();
for (i, entry) in entries.iter().enumerate() {
// Emit progress for large directories
if i % 100 == 0 {
app.emit("scan_progress", i).unwrap();
}
files.push(FileEntry::from_dir_entry(entry)?);
}
app.emit("scan_complete", files.len()).unwrap();
Ok(files)
}
#[tauri::command]
async fn copy_file(src: String, dest: String, app: AppHandle) -> Result<(), String> {
let src_path = Path::new(&src);
let dest_path = Path::new(&dest);
// Use async file operations for large files
let mut src_file = tokio::fs::File::open(&src_path).await
.map_err(|e| e.to_string())?;
let mut dest_file = tokio::fs::File::create(&dest_path).await
.map_err(|e| e.to_string())?;
// Stream copy with progress
let file_size = src_file.metadata().await
.map_err(|e| e.to_string())?.len();
let mut copied = 0u64;
while copied < file_size {
let chunk_size = tokio::io::copy(&mut src_file, &mut dest_file).await
.map_err(|e| e.to_string())?;
copied += chunk_size;
app.emit("copy_progress", (copied * 100) / file_size).unwrap();
}
Ok(())
}
What a novice would miss: Using blocking std::fs operations (freezes UI), forgetting progress events, not handling permission errors.
What an expert catches: Async file operations, progress tracking, proper error propagation, scoped capabilities.
QUALITY GATES
- All commands return Result<T, String> for proper error handling
- Async commands used for any I/O operations (file, network, database)
- Capabilities scoped to minimum required permissions per window
- App icons generated via
cargo tauri iconfor all required sizes - Bundle identifier follows reverse-domain format (com.company.app)
- Event listeners properly cleaned up with unlisten() calls
- State management uses Arc<Mutex> or Arc<RwLock> for thread safety
- No secrets or API keys stored in frontend JavaScript code
- CSP (Content Security Policy) configured in tauri.conf.json
- Tested on both macOS and Windows for rendering consistency
- Bundle size under 50MB for simple apps (check with
cargo tauri build) - All plugins registered in lib.rs Builder chain
- Minimum OS versions specified in bundle configuration
NOT-FOR BOUNDARIES
Do NOT use for:
- Browser-only web applications → Use standard web frameworks
- Mobile applications → Use tauri-mobile (experimental) or native mobile development
- Node.js compatibility required → Use Electron instead
- Pure command-line tools → Use rust-expert skill
- Complex video/audio processing → Use native platform frameworks
- Apps requiring embedded Chromium → Use Electron
Delegate to:
- Code signing and distribution → rust-app-distribution skill
- Cross-platform UI abstractions → cross-platform-desktop skill
- Advanced TypeScript patterns → typescript-advanced-patterns skill
- Database design and optimization → database-design skill
More from curiositech/windags-skills
kleppmann-data-intensive
Comprehensive guide to designing reliable, scalable data systems covering databases, streaming, and consistency
3beautiful-cli-design
|
2next-move
>
1admin-dashboard
Extend and modify the admin dashboard, developer portal, and operations console. Use when adding new admin tabs, metrics, monitoring features, or internal tools. Activates for dashboard development, analytics, user management, and internal tooling.
1color-contrast-auditor
Detects and fixes color contrast violations using WCAG 2.1 guidelines and perceptual analysis. Expert in contrast ratio calculation, color blindness simulation, and providing accessible alternatives. Activate on "check contrast", "color accessibility", "WCAG audit", "readability check", "contrast ratio", "hard to read", "can't see text". NOT for general color theory (use color-theory-palette-harmony-expert), brand color selection (use web-design-expert), or non-visual accessibility (use ux-friction-analyzer).
1web-design-expert
Creates unique web designs with brand identity, color palettes, typography, and modern UI/UX patterns. Use for brand identity development, visual design systems, layout composition, and responsive web design. Activate on "web design", "brand identity", "color palette", "UI design", "visual design", "layout". NOT for typography details (use typography-expert), color theory deep-dives (use color-theory-expert), design system tokens (use design-system-creator), or code implementation without design direction.
1