Skip to main content
The short rule: the frontend presents and interacts; Rust owns data, I/O and anything that must also work on a remote machine. The frontend never touches the disk, starts a process or opens a network connection itself; it asks the backend through typed commands.

What belongs in Rust

Work in Rust also follows the threading rules: long work never blocks the UI thread or a Tauri command thread. Use spawn_blocking or rayon and honour the request’s CancellationToken.

What belongs in the frontend

Splitting one feature across both

Many features have a cheap, I/O-heavy half in Rust and a light, data-shaping half in the UI. Spring request mappings in the HTTP Client are a good example:
  • Rust (crates/ide-host/src/ops/routes.rs): spring_route_sources walks the project with the usual ignore rules and returns the text of Java and Kotlin files that could declare a route, with file-count and byte caps. “The UI owns the annotation parser and the index it feeds, so this side stays a cheap scan.”
  • UI (src/features/http-client/spring/routeIndex.ts): parses the annotations, builds the request-path index, registers it as an endpoint provider, and drops the cache on fsChanged events for .java / .kt files.
Another: tree-sitter structure queries (ide-syntax) run in Rust against the cached syntax tree, while the editor decides when to use them as a fallback because the language server is unavailable.

Deciding for a new feature

Put it in Rust if any of these is true:
  • it reads or writes files, starts a process, or talks to the network;
  • it must work in a remote window (the project and its tools are on the other machine);
  • it scans more than the open documents, or can take more than a frame;
  • it enforces a security property (trust, permissions, validation of untrusted input);
  • a plugin, the MCP server or another backend crate needs the result.
Keep it in the frontend if it is about how something looks or responds to input, and works from data the backend already provides. When it lands in Rust, place it by domain: logic in the crate that owns the domain (or a new crates/ide-<domain>), the shared command implementation in ide-host::ops, and a thin adapter in src-tauri/src/commands/<domain>.rs. No domain logic in src-tauri. When it lands in the frontend, it is a feature folder under src/features/<name>/ that registers actions and contributions. It must not import another feature; see Frontend.