"The webview can ask. Only the core can act."
Who Runs What
Picture two brains. The webview brain thinks in the language of the screen: DOM, events, layout, your React tree. It is sandboxed — it cannot open a file, spawn a process, or read the network the way a server can. The core brain thinks in the language of the machine: files, sockets, OS APIs, threads. It is fully privileged. Tauri's entire design is about letting these two cooperate without letting the untrusted one (the webview, which might render remote or attacker-influenced content) reach straight into the privileged one.
So they don't call each other's functions directly. They send messages. The webview calls invoke('do_thing', { ... }); Tauri routes that to a Rust function you marked as a #[tauri::command]; the function runs in the core and returns a value that travels back to the webview as a resolved Promise.
Everything That Crosses Is Data
Because the two halves don't share memory, anything that crosses the bridge is serialized — turned into plain data (think JSON) on one side and rebuilt on the other. You cannot hand the webview a live file handle or a Rust struct with a database connection inside it. You hand it numbers, strings, arrays, and objects. This is the same discipline you already know from talking to an HTTP API: the wire carries data, not live references. Internalize it now and the bridge track will feel obvious.
Why This Is the Security Story Too
The message boundary isn't just plumbing — it's the fence. The webview can only invoke the exact commands you registered, and (as you'll see in security) only the ones a capability grants it. A bug or an injected script in your frontend can't rm -rf the disk, because the frontend has no disk access to abuse — it can only ask the core, and the core only answers requests it was told to allow.