FrameQuery
Technology

Why We Chose Rust and Tauri Over Electron for a Video Desktop App

Electron ships a whole browser. Tauri ships a native webview. For a video application that needs to decode RAW formats and manage large libraries, that difference matters more than you might think.

FrameQuery Team31 March 20266 min read

When we started building FrameQuery, one of the earliest decisions was the desktop application framework. The two serious options were Electron and Tauri. We chose Tauri with a Rust backend. Here is why, and what we learned along the way.

The Electron baseline

Electron is the dominant framework for cross-platform desktop apps. VS Code, Slack, Discord, Figma, Notion. It works by bundling Chromium (the browser engine behind Chrome) and Node.js together, then running your web app inside that bundled browser.

For many applications, this is fine. The developer experience is excellent. You write a web app, wrap it in Electron, and you have a desktop app that works on Windows, macOS, and Linux.

For a video application, Electron's trade-offs become problems.

Problem 1: Memory

Chromium is not a lightweight process. An empty Electron app starts at roughly 80 to 150 MB of RAM. That is before your application does anything. Add a few webviews, some state management, and a media player, and you are easily at 300 to 500 MB.

FrameQuery needs to handle large video libraries. Users have thousands of clips, extensive search indexes, and they preview video directly in the app. Every megabyte Electron spends on Chromium overhead is a megabyte not available for your actual work.

Tauri uses the operating system's native webview (WebView2 on Windows, WebKit on macOS and Linux) instead of bundling Chromium. The baseline memory footprint is dramatically lower: a Tauri app typically starts at 20 to 40 MB. That leaves more room for the things that actually matter, like loading search indexes and decoding video frames.

Problem 2: App size

An Electron app ships Chromium with every install. That is a 150 to 200 MB download before your application code adds anything. Users download a browser they already have, bundled inside your app.

Tauri's native webview approach means the framework itself adds roughly 3 to 5 MB to your installer. The FrameQuery installer is around 10 MB total. Users download less, install faster, and do not wonder why a video search tool is the size of a browser.

Problem 3: CPU-intensive work in Node.js

Electron's backend runs on Node.js. For I/O-bound tasks (HTTP requests, file reads, database queries), Node.js is capable. For CPU-bound tasks, it is a poor fit.

Video applications do a lot of CPU-bound work:

  • Decoding proprietary formats. R3D and BRAW files require vendor SDKs written in C/C++. Node.js can call native code via N-API or node-ffi, but the ergonomics are painful and the performance overhead is real.
  • Managing FFmpeg pipelines. Spawning FFmpeg processes and piping frame data through them is systems-level work.
  • Processing large search indexes. Loading and querying search indexes with millions of entries benefits from native speed.
  • Coordinating GPU acceleration. CUDA and Metal integration requires direct interaction with system APIs.

Node.js can technically do all of this via native addons, but at that point you are writing C++ anyway and losing the benefits of Node.js. You end up with the worst of both worlds: the overhead of Node.js plus the complexity of native code without the safety of a proper systems language.

Why Rust

Rust gave us three things we needed.

Native performance without the footguns

Rust compiles to native code. There is no runtime, no garbage collector, no interpreter. CPU-intensive operations run at the same speed as equivalent C or C++ code.

For video work, this matters. When we are decoding thousands of R3D frames through a GPU-accelerated pipeline, every millisecond of overhead per frame adds up. A garbage collector pause during a streaming decode is a dropped frame or a pipeline stall. Rust's ownership model eliminates GC entirely.

Safe FFI with C/C++ SDKs

FrameQuery integrates with the RED R3D SDK and the Blackmagic BRAW SDK, both written in C/C++. Calling C code from Rust is straightforward: we write C wrapper functions, use bindgen to generate Rust FFI bindings at compile time, and wrap those in safe Rust APIs.

The key advantage over C++ is that Rust's type system and ownership rules catch most FFI-related bugs at compile time. Use-after-free, double-free, data races, these are the kinds of errors that crash video applications in production. Rust makes them compile-time errors instead.

We still have unsafe blocks at the FFI boundary, that is unavoidable. But the unsafe code is contained in thin wrapper layers, and the rest of the application benefits from full safety guarantees.

Cross-platform without compromise

Rust's standard library and ecosystem handle cross-platform concerns well. Our codebase compiles on Windows, macOS, and Linux with platform-specific code limited to GPU backends (CUDA on Windows/Linux, Metal on macOS) and a few OS-specific file path handling details.

The build.rs script handles the messy parts: detecting CUDA availability, linking platform libraries, compiling Objective-C++ wrappers for Metal on macOS, generating COM headers on Windows. Application code stays clean.

Why Tauri specifically

Tauri is not the only way to build a desktop app with Rust. We could have gone fully native with a toolkit like egui or iced, or embedded a webview manually. Tauri gave us several advantages.

Web frontend, native backend

FrameQuery's UI is a React application with Tailwind CSS. The frontend team uses the same tools, frameworks, and workflows they would use for any web application. Hot module reloading works during development. The component library is extensive. Designers can inspect and iterate on the UI with standard browser dev tools.

The backend is pure Rust. Tauri's command system lets the frontend call Rust functions with typed arguments and return values. The frontend says "search for clips matching this query" and the Rust backend handles the actual searching: loading the Tantivy index, running the query, returning results.

This split means we get the development speed of web technologies for the UI and the performance of Rust for the heavy lifting.

Tauri 2 and mobile

Tauri 2 added mobile platform support (iOS and Android). While FrameQuery is desktop-focused, having a path to mobile without rewriting the backend is valuable. The Rust core would be the same; only the frontend would adapt to smaller screens.

Plugin ecosystem

Tauri's plugin system covers common desktop needs: file system access, OS dialogs, system tray, auto-updates, deep linking. These are well-maintained and save us from reimplementing platform-specific functionality.

Tantivy for search, SQLite for everything else

Two more architectural decisions worth mentioning.

Tantivy is a full-text search engine library written in Rust, inspired by Apache Lucene. It powers all of FrameQuery's search: transcript queries, scene descriptions, metadata matching. Because Tantivy is a Rust crate, it compiles directly into our binary with no external dependencies. Search is fast, local, and runs entirely in-process. No separate search server, no Elasticsearch cluster, no network round-trips.

SQLite handles everything that is not search: video metadata, source folders, processing status, settings, face clusters. SQLite is not a client-server database. It is a library that reads and writes directly to a file on disk. There is no daemon to manage, no port to configure, no Docker container to keep running.

Together, your FrameQuery data is a SQLite .db file plus Tantivy index files. For a local-first application, this is ideal:

  • Backups mean copying files
  • Migration means copying files to a new machine
  • Corruption recovery means restoring from a backup
  • Performance is excellent for our workload (read-heavy, single-writer)

The trade-offs

Tauri and Rust are not without downsides.

Compile times. Rust is slow to compile compared to Go, TypeScript, or most other languages. A clean build of FrameQuery's Rust backend takes minutes, not seconds. Incremental builds are faster, but the feedback loop is still slower than Node.js.

Smaller ecosystem. Electron's npm ecosystem is enormous. Almost any feature you need has a package. Rust's ecosystem is growing fast but is still smaller. We have written more code from scratch than we would have in Electron.

Steeper learning curve. Rust's ownership model has a real learning curve. Engineers coming from JavaScript or Python need time to become productive. The borrow checker catches real bugs, but it also rejects code that would be fine in other languages until you learn idiomatic patterns.

WebView inconsistencies. Using the OS native webview means dealing with rendering differences between WebView2 (Windows), WebKit (macOS), and WebKitGTK (Linux). Electron's bundled Chromium gives you identical rendering everywhere. In practice, the differences are minor and manageable with standard CSS techniques, but they exist.

We think these trade-offs are worth it. The performance, memory, and binary size improvements are real and measurable. For a video application that needs to decode RAW formats, manage large libraries, and coordinate GPU acceleration, Rust and Tauri give us a foundation that Electron could not.


Interested in a video search app that does not ship with its own browser? Join the waitlist to try FrameQuery.