DEV Community

Alex Spinov
Alex Spinov

Posted on

Tauri Has a Free Framework — Here's How to Build Desktop Apps 10x Smaller Than Electron

An Electron app on my Mac uses 300MB of RAM to show a to-do list. The same app built with Tauri uses 15MB. The installer? 3MB vs Electron's 150MB. Same web tech, same functionality, 10x smaller.

What Tauri Offers

Tauri (open source, free):

  • System webview — no bundled Chromium (that's why it's tiny)
  • Rust backend — fast, secure, memory-safe
  • Any frontend — React, Vue, Svelte, plain HTML
  • Cross-platform — macOS, Windows, Linux, iOS, Android
  • Auto-updater — built-in update mechanism
  • System tray — native tray icons and menus
  • File system access — read/write files securely
  • IPC — frontend ↔ Rust communication
  • 3-10 MB installers vs Electron's 100-200 MB

Quick Start

npm create tauri-app@latest
# Choose your frontend: React, Vue, Svelte, Solid, etc.

cd my-app
npm install
npm run tauri dev
Enter fullscreen mode Exit fullscreen mode

Rust Backend Commands

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

#[tauri::command]
async fn read_file(path: String) -> Result<String, String> {
    std::fs::read_to_string(&path).map_err(|e| e.to_string())
}

#[tauri::command]
async fn save_data(data: serde_json::Value) -> Result<(), String> {
    let path = dirs::data_dir().unwrap().join("myapp/data.json");
    std::fs::write(&path, serde_json::to_string_pretty(&data).unwrap())
        .map_err(|e| e.to_string())
}

fn main() {
    tauri::Builder::default()
        .invoke_handler(tauri::generate_handler![greet, read_file, save_data])
        .run(tauri::generate_context!())
        .expect("error running app");
}
Enter fullscreen mode Exit fullscreen mode

Frontend (React)

import { invoke } from '@tauri-apps/api/core';
import { open, save } from '@tauri-apps/plugin-dialog';
import { readTextFile, writeTextFile } from '@tauri-apps/plugin-fs';

function App() {
  const [result, setResult] = useState('');

  async function handleGreet() {
    const msg = await invoke('greet', { name: 'World' });
    setResult(msg);
  }

  async function handleOpenFile() {
    const path = await open({ filters: [{ name: 'Text', extensions: ['txt', 'md'] }] });
    if (path) {
      const content = await readTextFile(path);
      setResult(content);
    }
  }

  async function handleSaveFile() {
    const path = await save({ defaultPath: 'output.txt' });
    if (path) {
      await writeTextFile(path, result);
    }
  }

  return (
    <div>
      <button onClick={handleGreet}>Greet</button>
      <button onClick={handleOpenFile}>Open File</button>
      <button onClick={handleSaveFile}>Save File</button>
      <pre>{result}</pre>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

System Tray

use tauri::{SystemTray, SystemTrayMenu, SystemTrayMenuItem};

let tray_menu = SystemTrayMenu::new()
    .add_item(CustomMenuItem::new("show", "Show Window"))
    .add_native_item(SystemTrayMenuItem::Separator)
    .add_item(CustomMenuItem::new("quit", "Quit"));

let tray = SystemTray::new().with_menu(tray_menu);

tauri::Builder::default()
    .system_tray(tray)
    .on_system_tray_event(|app, event| {
        match event {
            SystemTrayEvent::MenuItemClick { id, .. } => match id.as_str() {
                "quit" => std::process::exit(0),
                "show" => app.get_window("main").unwrap().show().unwrap(),
                _ => {}
            },
            _ => {}
        }
    })
    .run(tauri::generate_context!())
Enter fullscreen mode Exit fullscreen mode

Build & Distribute

# Build for current platform
npm run tauri build
# Creates: .dmg (macOS), .msi (Windows), .AppImage (Linux)
# Size: 3-10 MB (!)

# Cross-compile
# Use GitHub Actions for multi-platform builds
Enter fullscreen mode Exit fullscreen mode

Tauri vs Electron

Tauri Electron
3-10 MB installer 100-200 MB
15 MB RAM 150-300 MB RAM
System webview Bundled Chromium
Rust backend (fast) Node.js backend
Security-first Full Node.js access

Need desktop data collection? Check out my web scraping actors on Apify — cloud-based scraping.

Need a desktop app? Email me at spinov001@gmail.com.

Top comments (0)