← Back to tutorials

Tauri AI Desktop Apps: Complete Integration Guide

Lightweight AI desktop apps with Tauri and Rust

Tauri AI Desktop Apps: Integration Guide

Tauri is the strongest pick for AI desktop apps in 2026 for one compounding reason: AI apps ship models or talk to local inference engines, and Tauri's Rust core gives you a real systems language next to your webview UI — plus binaries in the single-digit MB and noticeably lower RAM than Electron. This guide covers the three integration patterns: cloud APIs, talking to local Ollama, and embedding inference in-process.

Pattern 1: Cloud AI with secrets kept out of the webview

The cardinal rule: API keys never enter the frontend. The webview is inspectable; the Rust side is compiled. Calls go through Tauri commands:

rust
// src-tauri/src/lib.rs
#[tauri::command]
async fn ask_ai(prompt: String) -> Result {
    let client = reqwest::Client::new();
    let resp: serde_json::Value = client
        .post("https://api.openai.com/v1/chat/completions")
        .bearer_auth(std::env::var("OPENAI_API_KEY").map_err(|e| e.to_string())?)
        .json(&serde_json::json!({
            "model": "gpt-4o-mini",
            "messages": [{"role": "user", "content": prompt}]
        }))
        .send().await.map_err(|e| e.to_string())?
        .json().await.map_err(|e| e.to_string())?;
    Ok(resp["choices"][0]["message"]["content"].as_str().unwrap_or("").into())
}

typescript
// frontend
import { invoke } from '@tauri-apps/api/core';
const answer = await invoke('ask_ai', { prompt });

For user-supplied keys, store them with the OS keychain (via a keyring crate or store plugin) — never localStorage. For streaming, emit Tauri events from the Rust side per token (window.emit("token", chunk)) and listen in the frontend — same UX as SSE in a web app.

Pattern 2: Local models via Ollama (the pragmatic default)

Most "local AI" desktop apps don't embed a model — they talk to Ollama on localhost:11434, which handles model management, GPU acceleration, and updates for you:

rust
#[tauri::command]
async fn ask_local(prompt: String) -> Result {
    let resp: serde_json::Value = reqwest::Client::new()
        .post("http://localhost:11434/api/generate")
        .json(&serde_json::json!({ "model": "qwen2.5:7b", "prompt": prompt, "stream": false }))
        .send().await.map_err(|e| e.to_string())?
        .json().await.map_err(|e| e.to_string())?;
    Ok(resp["response"].as_str().unwrap_or("").into())
}

Production details that separate toys from real apps: detect whether Ollama is running at startup (hit /api/tags) and guide installation if not; optionally manage the Ollama process as a sidecar via Tauri's shell plugin; check the model is pulled before first use and stream pull progress to the UI.

Pattern 3: Embedded inference (no external dependency)

For a fully self-contained binary, run inference in-process from Rust — practical for small models (1-4B, quantized) on modern hardware:

  • llama.cpp bindings (e.g. the llama-cpp-2 crate) — the battle-tested path, GGUF models, GPU offload.
  • Candle (Hugging Face's Rust ML framework) — pure-Rust, clean integration, good model coverage.
  • Run generation on a background thread (Tauri's async commands keep the UI responsive) and emit tokens as events. The trade: you own model distribution (hundreds of MB to GB — use Tauri's updater or download-on-first-run), and you own hardware variance. Embed only when "zero external dependencies" is a hard product requirement; otherwise Pattern 2 is less maintenance.

    Why Tauri over Electron for this workload

    TauriElectron

    Binary size~3-10 MB (system webview)~80-150 MB (bundled Chromium) Base RAMLower (no bundled Chromium)Higher — and AI workloads are already RAM-hungry Native-perf inference✅ Rust in-processNode addons / child process (workable, clunkier) Secrets isolationCompiled Rust sideMain process (JS — easier to introspect) Rendering consistency⚠️ system webview varies per OS✅ identical Chromium everywhere Team skillsRust required for the coreAll JavaScript

    The honest counterpoints: webview inconsistency across OSes is real (test on all three), and if your team has zero Rust, Electron ships faster — full comparison in Electron AI desktop apps.

    FAQ

    Can I use the Vercel AI SDK inside Tauri? Yes for UI hooks — but route the actual API calls through Rust commands so keys stay out of the webview.

    Auto-updates with big models? Keep app binary and model artifacts separate: Tauri updater for the binary, content-addressed download-on-demand for models.

    Whisper/audio? Same three patterns apply — whisper.cpp has Rust bindings for embedding, or call a local server.


    *Last updated: June 2026.*

    Also available in 中文.

    Tauri AI Desktop Apps: Complete Integration Guide | AI Skill Navigation | AI Skill Navigation