Why We Built Everything in Rust + Tauri
The technical and philosophical reasons behind choosing Rust and Tauri for the entire Rusty Suite — and what we learned building 6 desktop apps with it.
Every app in the Rusty Suite runs on Rust + Tauri 2. Not Electron. Not Flutter. Not a web app pretending to be native. Here's why.
The Electron Problem
Electron ships an entire Chromium browser with every app. That's ~150MB of overhead before you write a single line of your own code. Your "lightweight note-taking app" consumes 300MB of RAM at idle.
Tauri uses the operating system's built-in webview (WebKitGTK on Linux, WebView2 on Windows, WKWebView on macOS). The result: binaries under 10MB, RAM usage that makes sense, and startup times measured in milliseconds.
Why Rust?
Three reasons:
-
Memory safety without garbage collection. No null pointer exceptions. No data races. The compiler catches entire categories of bugs before the code ever runs.
-
Performance that matches C/C++. SQLite queries, thumbnail generation, file scanning — all happen in native Rust, not in a JavaScript runtime.
-
A type system that prevents mistakes. When the Rust compiler accepts your code, you can be confident it won't segfault, leak memory, or corrupt data at runtime.
Privacy by Architecture
Tauri's security model is permission-based. Each app declares exactly which system capabilities it needs — file access, network requests, shell commands. Everything else is denied by default.
There's no "phone home" capability baked into the framework. No analytics SDK. No crash reporting that sends your data to someone's server. If an app doesn't declare network permissions, it physically cannot make network requests.
Your data stays on your machine because the architecture makes it impossible for it to leave.
What We Learned Building 6 Apps
The shared module pattern works. RustyPassport (achievements), RustyNotes (cross-app notes), RustyGotchi (virtual pet), and RustyBux (donation currency) are all Rust crates shared across every app via path dependencies. One codebase, one shared SQLite database per module, consistent behavior everywhere.
The hard part wasn't Rust — it was getting the React frontend and Rust backend to communicate cleanly through Tauri's invoke() bridge. We settled on a pattern: all API calls go through a single lib/api.ts file, all types through lib/types.ts, and the Rust side uses serde for automatic JSON serialization.
Six apps later, the pattern is rock solid. And every one of them starts in under a second.