Skip to content
STACK IT FAST

Tauri 2 + React + Vite (Rust Desktop App)

Curated rule Developer Tool & API · Internal Admin Tool · Collaboration & Productivity Updated Oct 2026 Which file does my tool read?
tauri-react-desktop.md

Desktop app rules for Tauri 2: React + Vite + TypeScript UI, typed Rust commands, least-privilege capabilities, SQLite in Rust, updater and signed CI builds.

Formats
4 files
AGENTS.md
47 lines
CLAUDE.md
16 lines
Languages
Rust, TypeScript
Updated
Oct 2026
Used by
4 projects
Install

Writes .claude/skills/tauri-react-desktop/SKILL.md

$ curl -s --create-dirs -o .claude/skills/tauri-react-desktop/SKILL.md https://stackitfast.com/rules/tauri-react-desktop/SKILL.md

Rule files

AGENTS.md· 47 lines · 3.5 KB
1# Project Architecture & Guidelines (Tauri 2 + React + Vite)
2
3## 1. System Architecture
4- **Shell**: Tauri 2 (system WebView, Rust core). Desktop targets: macOS, Windows, Linux.
5- **UI**: React + Vite + TypeScript (strict) in `src/`; TanStack Query for calling Rust commands; Tailwind CSS.
6- **Core**: Rust 2024 edition in `src-tauri/`. All file system, network, database and OS work happens here, never in the WebView.
7- **Data**: local SQLite owned by Rust (`sqlx` with the `sqlite` and `migrate` features) in the app data directory (`app.path().app_data_dir()`).
8- **Updates**: `tauri-plugin-updater` with signed release artifacts.
9
10## 2. Project Layout
11- `src-tauri/src/lib.rs`: `run()` builds the app: plugins, `.manage(state)`, `invoke_handler(tauri::generate_handler![...])`.
12- `src-tauri/src/commands/<feature>.rs`: `#[tauri::command]` functions, thin wrappers over `src-tauri/src/core/`.
13- `src-tauri/src/core/`: plain Rust domain logic with unit tests; no Tauri types.
14- `src-tauri/src/error.rs`: `AppError` (`thiserror`) with a `serde::Serialize` impl so commands can return `Result<T, AppError>`.
15- `src-tauri/capabilities/*.json`: per-window permission sets.
16- `src/lib/ipc.ts`: the only file that calls `invoke`; exports typed functions per command.
17
18## 3. Commands and IPC
19- Commands are `async` when they do I/O and return `Result<T, AppError>`; arguments and results derive `Serialize`/`Deserialize` with `#[serde(rename_all = "camelCase")]`.
20- Shared state goes through `app.manage(...)` and `State<'_, T>`; wrap mutable state in `tokio::sync::Mutex` or `RwLock`, never `static mut`.
21- Long-running work streams progress with `tauri::ipc::Channel<T>` or `app.emit(...)`; never block the main thread.
22- Keep TypeScript types in sync with Rust: generate bindings (for example with `tauri-specta`) or keep `src/lib/ipc.ts` as the single hand-written mirror reviewed with each command change.
23- The frontend never builds file paths or SQL; it calls a command with intent-level arguments.
24
25## 4. Security (least privilege)
26- Every window gets an explicit capability file listing only the permissions it uses (`core:window:default`, `updater:default`, ...). No wildcard permissions.
27- Keep the default CSP in `tauri.conf.json` strict; load no remote scripts.
28- Validate every command argument in Rust; treat the WebView as untrusted input.
29- Secrets live in the OS keychain (via a keyring plugin or crate), not in local storage or SQLite.
30
31## 5. Agent Loop (run after every change)
321. `cargo check --manifest-path src-tauri/Cargo.toml`.
332. `cargo clippy --manifest-path src-tauri/Cargo.toml --all-targets -- -D warnings`.
343. `cargo test --manifest-path src-tauri/Cargo.toml`.
354. `pnpm typecheck && pnpm test` for the UI.
365. When adding a command: register it in `generate_handler!`, add its permission to the capability file, add the typed wrapper in `ipc.ts`. Missing any of the three is the most common Tauri bug.
37- No `unwrap()`/`expect()` in commands; a panic in a command kills the app.
38
39## 6. Testing
40- Unit-test `core/` as plain Rust. Command wrappers stay thin enough not to need their own tests.
41- Mock `invoke` in Vitest (`@tauri-apps/api/mocks` `mockIPC`) for UI tests.
42- Smoke-test the packaged app on each OS in CI before a release.
43
44## 7. Build and Release
45- `pnpm tauri build` per target in a GitHub Actions matrix (`tauri-apps/tauri-action`).
46- Sign and notarise (Apple), sign (Windows), and sign updater artifacts with the Tauri signing key stored as a CI secret.
47- Bump the version in `tauri.conf.json` and `Cargo.toml` together.

Works with Claude Code · Cursor · Windsurf · AGY

Architecture notes

Architecture Overview

A desktop app with a web UI and a Rust core. Tauri 2 renders a React + Vite frontend in the system WebView and exposes typed Rust commands for everything that touches the operating system, the file system or the local SQLite database. The result is a small, signed, auto-updating binary for macOS, Windows and Linux.

Why it suits AI coding agents

  • A hard boundary. The UI asks for intents, Rust does the work. An agent can change either side and the compiler plus TypeScript catch most contract breaks.
  • Security is declarative. Capability files list exactly which commands each window may call, so an agent adding a feature also has to add the permission, which reviewers see in the diff.
  • Plain Rust core. Domain logic in core/ has no Tauri types and is unit-tested like any other crate.

In the directory

Hoppscotch ships a Tauri desktop app next to its web client, VoiceStudio uses Tauri alongside Electron, and RustDesk shows how far a Rust core can go on the desktop. For server-side Rust web stacks, see Building web apps in Rust in 2026.

Frequently asked questions

Tauri or Electron in 2026?

Tauri uses the operating system's WebView and a Rust core, so installers are typically a few megabytes and idle memory is far lower than Electron, which bundles Chromium and Node.js. Electron still wins when you need identical rendering on every OS or deep Node.js ecosystem access; several directory projects, such as VoiceStudio, ship both.

Do I need to know Rust to use Tauri?

Only for the native parts. The UI is ordinary React and TypeScript, and many apps need just a handful of Rust commands. Those commands are exactly where an AI agent benefits from the Rust compiler, which is why this rule keeps all OS and data access in Rust.

Why is my Tauri command not callable from the frontend?

In Tauri 2 a command must be registered in tauri::generate_handler! and allowed by a permission in a capability file for that window. Forgetting the capability is the most common cause of "command not allowed" errors.

Should the frontend use tauri-plugin-sql directly?

It can, but this rule keeps SQLite in Rust so the WebView never holds raw SQL access, queries are checked by sqlx at compile time, and the database schema has one owner. Use the plugin only for small apps where that boundary is not worth it.

Used in production

Explore all stacks