Skip to main content
Technology & EngineeringTauri283 lines

Tauri Fundamentals

Tauri 2.0 architecture, Rust backend with webview frontend, project setup with Cargo and npm, development workflow, and build targets for Windows, macOS, Linux, iOS, and Android.

Quick Summary23 lines
You are an expert in Tauri 2.0 desktop and mobile application development, covering architecture, project setup, and the full development lifecycle.

## Key Points

- **Treating Tauri like Electron**: Expecting Node.js APIs to be available in the frontend process. Tauri's frontend is a pure webview -- use Tauri commands or plugins for system access.
- **Putting business logic in the frontend**: Heavy computation or data processing belongs in Rust commands, not in the webview where it blocks the UI thread.
- **Ignoring platform differences**: WebView2 (Windows), WebKit (macOS), and WebKitGTK (Linux) have rendering differences. Test on all target platforms early.
- **Skipping the permission system**: Tauri 2.0 uses capability-based permissions. Requesting blanket permissions defeats the security model.
- **Building without release profile**: Debug builds are dramatically slower. Always test with `--release` before benchmarking or shipping.
1. Starts the frontend dev server (Vite by default)
2. Compiles the Rust backend
3. Opens the app window pointing to the dev server
4. Watches for Rust changes and recompiles
5. Frontend hot-reloads via Vite HMR

## Quick Example

```bash
# Generate all required icon sizes from a single 1024x1024 PNG
cargo tauri icon src-tauri/icons/app-icon.png
```
skilldb get tauri-skills/Tauri FundamentalsFull skill: 283 lines
Paste into your CLAUDE.md or agent config

Tauri Fundamentals — Tauri 2.0 Development

You are an expert in Tauri 2.0 desktop and mobile application development, covering architecture, project setup, and the full development lifecycle.

Core Philosophy

Tauri takes the opposite approach from Electron. Instead of bundling Chromium and Node.js with every app, Tauri uses the operating system's native webview (WebView2 on Windows, WebKit on macOS/Linux) and a Rust backend. This produces binaries that are typically 5-10 MB instead of 150+ MB, with significantly lower memory usage. The tradeoff is that you must handle cross-platform webview differences and write your backend logic in Rust rather than JavaScript.

The Tauri 2.0 architecture splits cleanly: the Rust "core" process handles system access, file I/O, and heavy computation, while the webview "frontend" process handles UI rendering. Communication between them flows through a typed IPC bridge. This separation enforces a security boundary -- the frontend cannot directly access the filesystem or network without explicit permission from the Rust side.

Design your app around this split from the start. Put business logic, data processing, and system interactions in Rust commands. Keep the frontend focused on presentation and user interaction. Resist the temptation to tunnel everything through JavaScript -- Rust's performance and safety make it the right place for anything beyond UI rendering.

Anti-Patterns

  • Treating Tauri like Electron: Expecting Node.js APIs to be available in the frontend process. Tauri's frontend is a pure webview -- use Tauri commands or plugins for system access.
  • Putting business logic in the frontend: Heavy computation or data processing belongs in Rust commands, not in the webview where it blocks the UI thread.
  • Ignoring platform differences: WebView2 (Windows), WebKit (macOS), and WebKitGTK (Linux) have rendering differences. Test on all target platforms early.
  • Skipping the permission system: Tauri 2.0 uses capability-based permissions. Requesting blanket permissions defeats the security model.
  • Building without release profile: Debug builds are dramatically slower. Always test with --release before benchmarking or shipping.

Project Setup

Prerequisites

Install Rust via rustup and Node.js (18+). On Linux, install WebKitGTK and related system dependencies:

# macOS -- Xcode command line tools
xcode-select --install

# Ubuntu/Debian
sudo apt install libwebkit2gtk-4.1-dev build-essential curl wget file \
  libxdo-dev libssl-dev libayatana-appindicator3-dev librsvg2-dev

# Windows -- WebView2 is included in Windows 10/11
# Install Rust from https://rustup.rs

Creating a New Project

# Using create-tauri-app (recommended)
npm create tauri-app@latest my-app
cd my-app

# Or with Cargo
cargo install create-tauri-app
cargo create-tauri-app my-app

The scaffolder asks for your frontend framework (React, Vue, Svelte, Solid, Vanilla, etc.) and package manager.

Project Structure

my-app/
├── src-tauri/                  # Rust backend
│   ├── Cargo.toml              # Rust dependencies
│   ├── tauri.conf.json         # Tauri configuration
│   ├── capabilities/           # Permission definitions
│   │   └── default.json
│   ├── src/
│   │   ├── main.rs             # Entry point (or lib.rs)
│   │   └── lib.rs              # Command definitions
│   ├── icons/                  # App icons
│   └── gen/                    # Generated platform code
├── src/                        # Frontend source
│   ├── main.ts
│   └── App.tsx
├── package.json
└── vite.config.ts

Configuration (tauri.conf.json)

{
  "$schema": "https://raw.githubusercontent.com/tauri-apps/tauri/dev/crates/tauri-cli/schema.json",
  "productName": "My App",
  "version": "0.1.0",
  "identifier": "com.mycompany.myapp",
  "build": {
    "beforeDevCommand": "npm run dev",
    "devUrl": "http://localhost:5173",
    "beforeBuildCommand": "npm run build",
    "frontendDist": "../dist"
  },
  "app": {
    "title": "My App",
    "windows": [
      {
        "label": "main",
        "width": 1024,
        "height": 768,
        "resizable": true,
        "fullscreen": false
      }
    ],
    "security": {
      "csp": "default-src 'self'; script-src 'self'"
    }
  },
  "bundle": {
    "active": true,
    "targets": "all",
    "icon": [
      "icons/32x32.png",
      "icons/128x128.png",
      "icons/128x128@2x.png",
      "icons/icon.icns",
      "icons/icon.ico"
    ]
  }
}

Development Workflow

Running in Development

# Start dev server with hot reload (frontend) and Rust recompilation
npm run tauri dev

# Or directly with Cargo
cargo tauri dev

# With specific frontend framework dev server
cargo tauri dev --port 3000

The dev workflow:

  1. Starts the frontend dev server (Vite by default)
  2. Compiles the Rust backend
  3. Opens the app window pointing to the dev server
  4. Watches for Rust changes and recompiles
  5. Frontend hot-reloads via Vite HMR

Building for Production

# Build for current platform
npm run tauri build

# Build specific bundle type
cargo tauri build --bundles deb,appimage  # Linux
cargo tauri build --bundles msi,nsis      # Windows
cargo tauri build --bundles dmg,app       # macOS

# Build with debug info
cargo tauri build --debug

Build Targets

PlatformBundle TypesNotes
WindowsMSI, NSIS, EXEWebView2 auto-installed if missing
macOSDMG, .app bundleUniversal binary (Intel + Apple Silicon)
LinuxAppImage, deb, rpmRequires WebKitGTK at runtime
iOS.ipaVia cargo tauri ios build
Android.apk, .aabVia cargo tauri android build

Basic Application Structure

Rust Entry Point (src-tauri/src/lib.rs)

use tauri::Manager;

#[tauri::command]
fn greet(name: &str) -> String {
    format!("Hello, {}! Welcome to Tauri.", name)
}

#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
    tauri::Builder::default()
        .plugin(tauri_plugin_opener::init())
        .invoke_handler(tauri::generate_handler![greet])
        .setup(|app| {
            // Initialization logic here
            let window = app.get_webview_window("main").unwrap();
            window.set_title("My Tauri App")?;
            Ok(())
        })
        .run(tauri::generate_context!())
        .expect("error while running tauri application");
}

Frontend Invocation

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

async function greetUser() {
  const message = await invoke<string>("greet", { name: "World" });
  console.log(message); // "Hello, World! Welcome to Tauri."
}

Cargo Dependencies (src-tauri/Cargo.toml)

[package]
name = "my-app"
version = "0.1.0"
edition = "2021"

[dependencies]
tauri = { version = "2", features = [] }
tauri-plugin-opener = "2"
serde = { version = "1", features = ["derive"] }
serde_json = "1"

[build-dependencies]
tauri-build = { version = "2", features = [] }

[profile.release]
panic = "abort"
codegen-units = 1
lto = true
opt-level = "s"       # Optimize for size
strip = true

Icon Generation

# Generate all required icon sizes from a single 1024x1024 PNG
cargo tauri icon src-tauri/icons/app-icon.png

Debugging

# Open webview devtools in dev mode
# On macOS: Cmd+Option+I
# On Windows/Linux: Ctrl+Shift+I (or F12)

# Enable Rust logging
RUST_LOG=debug cargo tauri dev

# Build with debug symbols for release
cargo tauri build --debug

Environment Detection

fn run() {
    tauri::Builder::default()
        .setup(|app| {
            if cfg!(debug_assertions) {
                // Development mode
                println!("Running in development mode");
            } else {
                // Production mode
                println!("Running in production mode");
            }

            // Check platform
            if cfg!(target_os = "macos") {
                println!("Running on macOS");
            } else if cfg!(target_os = "windows") {
                println!("Running on Windows");
            } else if cfg!(target_os = "linux") {
                println!("Running on Linux");
            }

            Ok(())
        })
        .run(tauri::generate_context!())
        .expect("error while running tauri application");
}

Install this skill directly: skilldb add tauri-skills

Get CLI access →