Try Live
Add Docs
Rankings
Pricing
Docs
Install
Theme
Install
Docs
Pricing
More...
More...
Try Live
Rankings
Enterprise
Create API Key
Add Docs
Tauri
https://github.com/tauri-apps/tauri
Admin
Build smaller, faster, and more secure desktop and mobile applications with a web frontend.
Tokens:
42,740
Snippets:
307
Trust Score:
9.5
Update:
3 weeks ago
Context
Skills
Chat
Benchmark
67.4
Suggestions
Latest
Show doc for...
Code
Info
Show Results
Context Summary (auto-generated)
Raw
Copy
Link
# Tauri Tauri is a framework for building tiny, blazing fast binaries for all major desktop and mobile platforms. Developers can integrate any front-end framework that compiles to HTML, JS and CSS for building their user interface. The backend of the application is a Rust-sourced binary with an API that the front-end can interact with via Inter-Process Communication (IPC). Tauri provides a secure bridge between the frontend and native system capabilities. The framework supports Windows, macOS, Linux, iOS, and Android platforms. Key features include small binary sizes (as low as 600KB), built-in auto-updater, system tray support, and a robust plugin ecosystem. Tauri v2 introduces a permission-based Access Control List (ACL) system for enhanced security, mobile platform support, and improved multi-window and multi-webview capabilities. ## Core APIs - Rust Backend ### Creating a Tauri Application The `tauri::Builder` is the main entry point for configuring and launching a Tauri application. It allows you to register commands, manage state, add plugins, and configure window settings. ```rust use tauri::{command, State, Manager}; use std::sync::Mutex; // Define application state struct AppState { counter: Mutex<i32>, } // Define a command that can be invoked from the frontend #[command] fn greet(name: &str) -> String { format!("Hello, {}! Welcome to Tauri.", name) } // Command with state access #[command] fn increment_counter(state: State<AppState>) -> i32 { let mut counter = state.counter.lock().unwrap(); *counter += 1; *counter } // Async command with error handling #[command] async fn fetch_data(url: String) -> Result<String, String> { // Simulated async operation Ok(format!("Fetched data from: {}", url)) } fn main() { tauri::Builder::default() .manage(AppState { counter: Mutex::new(0) }) .invoke_handler(tauri::generate_handler![ greet, increment_counter, fetch_data ]) .setup(|app| { // Access the app handle during setup let handle = app.handle(); println!("App identifier: {}", handle.config().identifier); Ok(()) }) .run(tauri::generate_context!()) .expect("error while running tauri application"); } ``` ### State Management Tauri provides type-safe state management that can be accessed from any command handler. State must implement `Send + Sync` and is typically wrapped in synchronization primitives for mutability. ```rust use tauri::{command, State, Manager}; use std::sync::Mutex; use std::collections::HashMap; // Complex state with multiple fields struct Database { users: Mutex<HashMap<u64, String>>, connection_count: Mutex<u32>, } #[command] fn add_user(id: u64, name: String, db: State<Database>) -> Result<(), String> { let mut users = db.users.lock().map_err(|e| e.to_string())?; users.insert(id, name); Ok(()) } #[command] fn get_user(id: u64, db: State<Database>) -> Option<String> { let users = db.users.lock().ok()?; users.get(&id).cloned() } #[command] fn get_connection_count(db: State<Database>) -> u32 { *db.connection_count.lock().unwrap() } fn main() { tauri::Builder::default() .manage(Database { users: Mutex::new(HashMap::new()), connection_count: Mutex::new(0), }) .invoke_handler(tauri::generate_handler![add_user, get_user, get_connection_count]) .run(tauri::generate_context!()) .expect("error while running tauri application"); } ``` ### Event System - Emitting and Listening Tauri's event system allows bidirectional communication between the Rust backend and JavaScript frontend. Events can be emitted globally or to specific windows/webviews. ```rust use tauri::{AppHandle, Emitter, Listener, Manager}; use serde::{Serialize, Deserialize}; #[derive(Clone, Serialize, Deserialize)] struct DownloadProgress { file_name: String, progress: u32, total: u32, } #[tauri::command] fn start_download(app: AppHandle, file_name: String) { // Spawn async task for download simulation tauri::async_runtime::spawn(async move { for i in 0..=100 { // Emit progress to all listeners app.emit("download-progress", DownloadProgress { file_name: file_name.clone(), progress: i, total: 100, }).unwrap(); tokio::time::sleep(std::time::Duration::from_millis(50)).await; } // Emit completion event app.emit("download-complete", &file_name).unwrap(); }); } fn main() { tauri::Builder::default() .setup(|app| { // Listen for events from the frontend app.listen("user-action", |event| { println!("Received user action: {:?}", event.payload()); }); // Listen once for a specific event let handle = app.handle().clone(); app.once("app-ready", move |_| { handle.emit("backend-ready", ()).unwrap(); }); Ok(()) }) .invoke_handler(tauri::generate_handler![start_download]) .run(tauri::generate_context!()) .expect("error while running tauri application"); } ``` ### Window Management Create, manipulate, and interact with application windows programmatically from the Rust backend. ```rust use tauri::{AppHandle, Manager, WebviewUrl, WebviewWindowBuilder}; #[tauri::command] async fn create_new_window(app: AppHandle) -> Result<(), String> { WebviewWindowBuilder::new(&app, "settings", WebviewUrl::App("settings.html".into())) .title("Settings") .inner_size(600.0, 400.0) .resizable(true) .center() .build() .map_err(|e| e.to_string())?; Ok(()) } #[tauri::command] async fn get_window_info(app: AppHandle, label: String) -> Result<WindowInfo, String> { let window = app.get_webview_window(&label) .ok_or_else(|| format!("Window '{}' not found", label))?; let position = window.outer_position().map_err(|e| e.to_string())?; let size = window.outer_size().map_err(|e| e.to_string())?; Ok(WindowInfo { label: window.label().to_string(), x: position.x, y: position.y, width: size.width, height: size.height, }) } #[derive(serde::Serialize)] struct WindowInfo { label: String, x: i32, y: i32, width: u32, height: u32, } #[tauri::command] async fn close_window(app: AppHandle, label: String) -> Result<(), String> { if let Some(window) = app.get_webview_window(&label) { window.close().map_err(|e| e.to_string())?; } Ok(()) } ``` ### Plugin System Create custom plugins to extend Tauri's functionality with reusable modules that can be shared across applications. ```rust use tauri::{ plugin::{Builder, TauriPlugin}, Runtime, AppHandle, Manager, }; use serde::de::DeserializeOwned; // Plugin configuration #[derive(serde::Deserialize)] struct PluginConfig { api_key: Option<String>, timeout: Option<u64>, } // Plugin commands #[tauri::command] async fn plugin_fetch<R: Runtime>( app: AppHandle<R>, endpoint: String, ) -> Result<String, String> { // Access plugin state or config here Ok(format!("Fetched from: {}", endpoint)) } // Create the plugin pub fn init<R: Runtime>() -> TauriPlugin<R> { Builder::new("my-plugin") .invoke_handler(tauri::generate_handler![plugin_fetch]) .setup(|app, api| { // Plugin initialization let config: PluginConfig = api.config().clone(); println!("Plugin initialized with config: {:?}", config.api_key); Ok(()) }) .on_window_ready(|window| { println!("Window {} is ready", window.label()); }) .on_event(|app, event| { // Handle app events match event { tauri::RunEvent::Ready => { println!("App is ready!"); } tauri::RunEvent::ExitRequested { api, .. } => { // Optionally prevent exit // api.prevent_exit(); } _ => {} } }) .build() } // Usage in main.rs: // fn main() { // tauri::Builder::default() // .plugin(my_plugin::init()) // .run(tauri::generate_context!()) // .expect("error while running tauri application"); // } ``` ## JavaScript API ### Invoking Commands The `invoke` function sends messages to the Rust backend and receives responses. It supports typed arguments and return values. ```typescript import { invoke } from '@tauri-apps/api/core'; // Simple command invocation async function greetUser(name: string): Promise<string> { const greeting = await invoke<string>('greet', { name }); console.log(greeting); // "Hello, John! Welcome to Tauri." return greeting; } // Command with complex arguments interface User { id: number; name: string; email: string; } async function createUser(user: User): Promise<boolean> { try { const result = await invoke<boolean>('create_user', { user }); return result; } catch (error) { console.error('Failed to create user:', error); return false; } } // Async command with progress reporting async function downloadFile(url: string): Promise<void> { await invoke('download_file', { url }); } // Command with optional parameters async function searchItems(query: string, limit?: number): Promise<string[]> { return await invoke<string[]>('search_items', { query, limit: limit ?? 10 }); } ``` ### Event System Listen for and emit events between the frontend and backend for reactive communication patterns. ```typescript import { listen, emit, once, emitTo } from '@tauri-apps/api/event'; interface ProgressPayload { fileName: string; progress: number; total: number; } // Listen to events from backend async function setupEventListeners() { // Continuous listener const unlisten = await listen<ProgressPayload>('download-progress', (event) => { console.log(`Download progress: ${event.payload.progress}/${event.payload.total}`); updateProgressBar(event.payload.progress / event.payload.total * 100); }); // One-time listener await once<string>('download-complete', (event) => { console.log(`Download completed: ${event.payload}`); showNotification('Download Complete', event.payload); }); // Return cleanup function return () => { unlisten(); }; } // Emit events to backend async function notifyBackend() { // Emit to all listeners await emit('user-action', { action: 'click', target: 'submit-button' }); // Emit to specific window await emitTo('settings', 'config-updated', { theme: 'dark' }); } // React/Vue component example with cleanup function DownloadComponent() { useEffect(() => { const cleanup = setupEventListeners(); return () => cleanup.then(fn => fn()); }, []); return <div>...</div>; } ``` ### Window Management Create and manipulate windows from the JavaScript frontend. ```typescript import { Window, getCurrentWindow, getAllWindows } from '@tauri-apps/api/window'; // Get current window and manipulate it async function windowOperations() { const currentWindow = getCurrentWindow(); // Window properties console.log('Window label:', currentWindow.label); // Minimize, maximize, close await currentWindow.minimize(); await currentWindow.maximize(); await currentWindow.unmaximize(); // Set window properties await currentWindow.setTitle('New Title'); await currentWindow.setResizable(false); await currentWindow.setFullscreen(true); // Position and size await currentWindow.setPosition({ x: 100, y: 100 }); await currentWindow.setSize({ width: 800, height: 600 }); await currentWindow.center(); // Get window info const position = await currentWindow.outerPosition(); const size = await currentWindow.outerSize(); const scaleFactor = await currentWindow.scaleFactor(); } // Create new window async function createSettingsWindow() { const settingsWindow = new Window('settings', { url: 'settings.html', title: 'Settings', width: 600, height: 400, resizable: true, center: true, }); // Listen for window events settingsWindow.once('tauri://created', () => { console.log('Settings window created'); }); settingsWindow.once('tauri://error', (e) => { console.error('Failed to create window:', e); }); } // Window event listeners async function setupWindowEvents() { const window = getCurrentWindow(); await window.listen('tauri://close-requested', async (event) => { const confirmed = await confirm('Are you sure you want to close?'); if (confirmed) { await window.close(); } }); await window.listen('tauri://focus', () => { console.log('Window focused'); }); await window.listen('tauri://blur', () => { console.log('Window lost focus'); }); } ``` ### Channel API for Streaming Data Use channels for efficient streaming of data from Rust to JavaScript, particularly useful for progress reporting or real-time data. ```typescript import { Channel, invoke } from '@tauri-apps/api/core'; interface StreamChunk { data: string; index: number; isLast: boolean; } // Create a channel for receiving streamed data async function streamData() { const channel = new Channel<StreamChunk>(); channel.onmessage = (chunk) => { console.log(`Received chunk ${chunk.index}: ${chunk.data}`); if (chunk.isLast) { console.log('Stream complete'); } }; // Pass the channel to the backend command await invoke('stream_large_file', { filePath: '/path/to/file', channel }); } // Rust backend for streaming // #[tauri::command] // async fn stream_large_file(file_path: String, channel: Channel<StreamChunk>) -> Result<(), String> { // for (i, chunk) in read_file_chunks(&file_path).enumerate() { // channel.send(StreamChunk { // data: chunk, // index: i, // is_last: false, // }).unwrap(); // } // channel.send(StreamChunk { data: String::new(), index: 0, is_last: true }).unwrap(); // Ok(()) // } ``` ### App Information and Utilities Access application metadata and system information. ```typescript import { getName, getVersion, getTauriVersion, getIdentifier, show, hide, setTheme } from '@tauri-apps/api/app'; import { convertFileSrc } from '@tauri-apps/api/core'; async function displayAppInfo() { const name = await getName(); const version = await getVersion(); const tauriVersion = await getTauriVersion(); const identifier = await getIdentifier(); console.log(`${name} v${version}`); console.log(`Tauri: ${tauriVersion}`); console.log(`Identifier: ${identifier}`); } // Theme management async function toggleTheme(theme: 'light' | 'dark' | null) { await setTheme(theme); // null follows system theme } // Convert file path to URL for webview function loadLocalImage(filePath: string): string { // Converts '/path/to/image.png' to 'asset://localhost/path/to/image.png' const assetUrl = convertFileSrc(filePath); return assetUrl; } // Usage in HTML // <img src={loadLocalImage('/Users/me/Pictures/photo.png')} /> ``` ### Path Utilities Work with file system paths across different platforms. ```typescript import { appDataDir, appConfigDir, appCacheDir, documentDir, downloadDir, join, resolve, basename, dirname } from '@tauri-apps/api/path'; async function pathExamples() { // Get platform-specific directories const appData = await appDataDir(); // ~/Library/Application Support/com.example.app (macOS) const config = await appConfigDir(); // ~/Library/Application Support/com.example.app (macOS) const cache = await appCacheDir(); // ~/Library/Caches/com.example.app (macOS) const documents = await documentDir(); // ~/Documents const downloads = await downloadDir(); // ~/Downloads // Path manipulation const configPath = await join(appData, 'config', 'settings.json'); const absolutePath = await resolve(configPath); const fileName = await basename(configPath); // 'settings.json' const parentDir = await dirname(configPath); // '{appData}/config' console.log(`Config file: ${configPath}`); console.log(`Absolute: ${absolutePath}`); } ``` ## CLI Commands ### tauri init Initialize a new Tauri project in an existing frontend project directory. ```bash # Initialize Tauri in current directory cargo tauri init # Initialize with specific options cargo tauri init --app-name "My App" --ci ``` ### tauri dev Start the development server with hot-reload support. ```bash # Start development server cargo tauri dev # With specific features cargo tauri dev --features custom-protocol # Target specific platform cargo tauri dev --target aarch64-apple-darwin # Pass additional cargo arguments cargo tauri dev -- --release ``` ### tauri build Build the application for production and create distributable bundles. ```bash # Build release version cargo tauri build # Build with debug symbols cargo tauri build --debug # Build specific bundles only cargo tauri build --bundles deb,appimage # Build for specific target cargo tauri build --target x86_64-pc-windows-msvc # Build with custom config cargo tauri build --config ./custom-config.json ``` ### tauri add Add a Tauri plugin to the project. ```bash # Add official plugins cargo tauri add fs cargo tauri add dialog cargo tauri add shell cargo tauri add http # The command automatically: # 1. Adds Rust crate to Cargo.toml # 2. Adds npm package to package.json # 3. Updates capabilities if needed ``` ### tauri icon Generate application icons from a source image. ```bash # Generate all icon sizes from source cargo tauri icon ./app-icon.png # Specify output directory cargo tauri icon ./app-icon.png --output ./icons ``` ## Configuration ### tauri.conf.json Structure The main configuration file that controls all aspects of your Tauri application. ```json { "$schema": "https://schema.tauri.app/config/2", "productName": "My Tauri App", "version": "1.0.0", "identifier": "com.company.myapp", "build": { "frontendDist": "../dist", "devUrl": "http://localhost:5173", "beforeDevCommand": "npm run dev", "beforeBuildCommand": "npm run build" }, "app": { "withGlobalTauri": true, "windows": [ { "label": "main", "title": "My Tauri App", "width": 1024, "height": 768, "resizable": true, "fullscreen": false, "center": true } ], "security": { "csp": { "default-src": "'self'", "connect-src": "ipc: http://ipc.localhost", "img-src": "'self' asset: http://asset.localhost blob: data:" }, "assetProtocol": { "enable": true, "scope": { "allow": ["$APPDATA/**", "$RESOURCE/**"], "deny": ["$APPDATA/secrets/**"] } } } }, "bundle": { "active": true, "icon": [ "icons/32x32.png", "icons/128x128.png", "icons/icon.icns", "icons/icon.ico" ], "targets": ["dmg", "nsis", "deb", "appimage"], "macOS": { "minimumSystemVersion": "10.13" }, "windows": { "nsis": { "installMode": "currentUser" } } }, "plugins": { "shell": { "open": true } } } ``` ### Capabilities Configuration Define permissions for your application using capability files in `src-tauri/capabilities/`. ```json { "$schema": "https://schema.tauri.app/config/2/capability", "identifier": "main-capability", "description": "Main application capability", "windows": ["main"], "permissions": [ "core:default", "shell:allow-open", "dialog:allow-open", "dialog:allow-save", "fs:allow-read", "fs:allow-write", { "identifier": "fs:scope", "allow": [ "$APPDATA/**", "$DOCUMENT/**" ] } ] } ``` ## Summary Tauri provides a comprehensive solution for building cross-platform desktop and mobile applications using web technologies for the frontend and Rust for the backend. The primary use cases include building lightweight desktop applications, creating secure applications with fine-grained permissions, and developing applications that need native system access. The framework excels at scenarios requiring small bundle sizes, strong security guarantees, and cross-platform deployment. Integration patterns typically follow a frontend-backend separation where the UI is built with any web framework (React, Vue, Svelte, etc.) and communicates with the Rust backend through IPC commands and events. State management flows from managed Rust state to the frontend through commands, while real-time updates use the event system or channels for streaming data. Plugins extend functionality in a modular way, and the configuration system allows fine-tuned control over security, bundling, and platform-specific behavior. For production deployments, the CLI toolchain handles building optimized bundles for all target platforms with proper code signing and notarization support.