Skip to content

The Bridge: Calling Rust from JavaScript

The true power of Tauri comes from combining the easy UI development of the web with the raw performance of Rust. To do this, we use IPC (Inter-Process Communication). In Tauri, we call this the Command system.

A command is simply a Rust function annotated with the #[tauri::command] macro. This macro handles the serialization of data automatically.

// src-tauri/src/lib.rs or main.rs
#[tauri::command]
fn greet(name: &str) -> String {
format!("Hello, {}! You've been greeted from Rust!", name)
}

Defining the function isn’t enough; you must tell Tauri about it. We register commands inside the tauri::Builder invoke handler, usually found in your lib.rs (for v2 mobile compatibility structure) or main.rs.

src-tauri/src/lib.rs
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
tauri::Builder::default()
// Register the command here
.invoke_handler(tauri::generate_handler![greet])
.run(tauri::generate_context!())
.expect("error while running tauri application");
}

On the JavaScript side, we use the invoke function provided by the @tauri-apps/api package. This function returns a Promise, making it easy to handle asynchronous data flow.

First, ensure you have the API installed (if not using the default template):

Terminal window
npm install @tauri-apps/api

Then, call the command:

import { invoke } from '@tauri-apps/api/core';
async function callGreet() {
// The first argument is the command name (fn name in Rust)
// The second argument is an object matching the Rust arguments
const message = await invoke('greet', { name: 'World' });
console.log(message); // Prints: Hello, World! You've been greeted from Rust!
}

Rust commands are asynchronous by nature when called from the frontend. This is excellent for heavy computations (like image processing or database queries) because it ensures your UI never freezes while waiting for the backend.

You can define your Rust function as async fn as well, and Tauri will handle the await logic seamlessly across the bridge.

#[tauri::command]
async fn perform_heavy_task() -> String {
// Simulate work
std::thread::sleep(std::time::Duration::from_secs(2));
"Task Complete".to_string()
}