Your Electron app ships a 150MB installer. It uses 300MB of RAM to show a settings page. Your users have 3 Electron apps open and their laptop fan sounds like a jet engine.
What if your desktop app was 3MB, used 30MB of RAM, and also ran on iOS and Android?
That's Tauri 2.
Tauri 2 vs Electron
| Metric | Electron | Tauri 2 |
|---|---|---|
| App size | 85-200 MB | 2-6 MB |
| RAM usage (idle) | 150-300 MB | 20-40 MB |
| Startup time | 2-5s | 0.3-0.8s |
| Mobile support | No | iOS + Android |
| Backend language | JavaScript | Rust |
| Bundled runtime | Chromium + Node.js | System WebView |
The secret: Tauri uses the system's built-in WebView instead of shipping an entire browser.
Quick Start
npm create tauri-app@latest
cd tauri-app && npm install && npm run tauri dev
Architecture: Web Frontend + Rust Backend
my-app/
src/ # Your web app (React/Vue/Svelte/vanilla)
App.tsx
main.tsx
src-tauri/ # Rust backend
src/
main.rs # App entry + commands
lib.rs # Business logic
Cargo.toml
tauri.conf.json # App configuration
Your existing React/Vue/Svelte app becomes the frontend. Rust handles system operations.
Calling Rust From JavaScript
// src-tauri/src/main.rs
#[tauri::command]
fn read_file(path: String) -> Result<String, String> {
std::fs::read_to_string(&path).map_err(|e| e.to_string())
}
#[tauri::command]
async fn fetch_data(url: String) -> Result<String, String> {
reqwest::get(&url)
.await
.map_err(|e| e.to_string())?
.text()
.await
.map_err(|e| e.to_string())
}
fn main() {
tauri::Builder::default()
.invoke_handler(tauri::generate_handler![read_file, fetch_data])
.run(tauri::generate_context!())
.expect("error while running app");
}
// Frontend — call Rust functions like async JS
import { invoke } from "@tauri-apps/api/core";
const content = await invoke<string>("read_file", { path: "/tmp/data.txt" });
const apiData = await invoke<string>("fetch_data", { url: "https://api.example.com/data" });
Tauri 2: Mobile Support
# Initialize mobile targets
npm run tauri ios init
npm run tauri android init
# Run on iOS simulator
npm run tauri ios dev
# Run on Android emulator
npm run tauri android dev
# Build for release
npm run tauri ios build
npm run tauri android build
Same codebase. Desktop + iOS + Android. The web frontend renders in a native WebView, Rust commands work across all platforms.
System Tray, Notifications, Deep Links
use tauri::{
menu::{Menu, MenuItem},
tray::TrayIconBuilder,
};
fn main() {
tauri::Builder::default()
.setup(|app| {
let menu = Menu::with_items(app, &[
&MenuItem::new(app, "Show", true, None::<&str>)?,
&MenuItem::new(app, "Quit", true, None::<&str>)?,
])?;
TrayIconBuilder::new()
.menu(&menu)
.icon(app.default_window_icon().unwrap().clone())
.build(app)?;
Ok(())
})
.run(tauri::generate_context!())
.unwrap();
}
When to Choose Tauri 2
Choose Tauri when:
- App size and RAM matter (distributing to users with limited bandwidth)
- You need desktop + mobile from one codebase
- You want system-level performance (file I/O, networking, crypto) via Rust
- You're building a utility app, not a browser-based SaaS
Skip Tauri when:
- You need pixel-perfect cross-browser rendering (WebView varies by OS)
- Your team has zero Rust experience and can't invest time learning
- You rely on Node.js native modules
The Bottom Line
Tauri 2 proves that desktop + mobile apps don't need to ship a browser. Your users get a faster, lighter app. You get a single codebase across 5 platforms.
Start here: v2.tauri.app
Need custom data extraction, scraping, or automation? I build tools that collect and process data at scale — 78 actors on Apify Store and 265+ open-source repos. Email me: Spinov001@gmail.com | My Apify Actors
Top comments (0)