Process Plugin

Use the Tauri Process Plugin to programmatically exit and restart your application from JavaScript or Rust.

The Process Plugin gives your Tauri application direct control over its own lifecycle—exiting cleanly with a status code or relaunching itself entirely. Unlike the Shell API, which opens resources and can spawn child processes, this plugin deals only with the current application process. It is a tiny but essential tool for graceful shutdowns, recovery flows, and restarting after configuration changes.

Supported Platforms

The plugin requires a Rust version of at least 1.77.2. It works on all major desktop platforms.

PlatformSupported
Windows
macOS
Linux
Android
iOS

Mobile platforms are not supported because mobile operating systems manage app lifecycles differently and do not allow arbitrary exit or restart from within the application.

What You Can Do with This Plugin

The plugin exposes two operations:

  • Exit – terminates the application with a status code you provide.
  • Relaunch (restart) – shuts down the current process and starts a fresh instance of the same app.

These map to exit and relaunch in JavaScript, and exit / restart in Rust. The names differ slightly between environments, but the behavior is the same.

Think of it as your app’s emergency brake and its "try again" button, both accessible from code.

Setup

You need to add the plugin to both the Rust backend and the JavaScript frontend. If you use the automatic CLI command, both sides are handled for you. The Process Plugin introduction explains when to reach for exit versus relaunch before you wire it up.

1

Step 1: Add the plugin to your project

The CLI automates the entire process. Run one of the following commands in your project root, depending on your package manager:

npm run tauri add process
# or
yarn run tauri add process
# or
pnpm tauri add process
# or
bun tauri add process

This installs the Rust crate (tauri-plugin-process) and the npm package (@tauri-apps/plugin-process), then registers the plugin in your lib.rs automatically.

2

Step 2 (Manual): Register the Rust plugin

If you are adding the dependency manually, first include it in src-tauri/Cargo.toml:

[dependencies]
tauri-plugin-process = "2"

Then register the plugin in your run() function:

#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
    tauri::Builder::default()
        .plugin(tauri_plugin_process::init())
        .run(tauri::generate_context!())
        .expect("error while running tauri application");
}

Order of Plugins:

Plugin registration order rarely matters for the process plugin, but if your app uses other plugins that need cleanup on exit, register this one last. That way hooks from earlier plugins still run before the app terminates.

3

Step 3: Install the JavaScript bindings

The npm package provides the JavaScript API. Install it with your package manager:

npm install @tauri-apps/plugin-process
# or
yarn add @tauri-apps/plugin-process
# or
pnpm add @tauri-apps/plugin-process
# or
bun add @tauri-apps/plugin-process

This step is already done for you if you used the automatic tauri add command.

Verification:

After setup, build your app once. If tauri dev or cargo build completes without errors, the plugin is properly registered. You can verify from JavaScript by checking that import { exit } from '@tauri-apps/plugin-process' does not throw an error.

Usage

The plugin provides two functions. You’ll use them depending on whether you are calling from the frontend (JavaScript/TypeScript) or from the Rust backend.

import { exit, relaunch } from '@tauri-apps/plugin-process';
// Terminate the app with exit code 0 (success)
await exit(0);
// Restart the app completely
await relaunch();

exit takes a status code: 0 means success, any non-zero value indicates an error. relaunch causes the current process to shut down and a brand new instance of the same executable to start.

If you enabled withGlobalTauri in your tauri.conf.json, you can also use the global API:

const { exit, relaunch } = window.__TAURI__.process;
await exit(0);

Async completion is not guaranteed:

Both functions return a Promise that resolves immediately after requesting the operation. The actual termination or relaunch may happen asynchronously. Do not rely on code after await exit() ever running; in many environments it never will.

When you run relaunch (or restart), Tauri sends a request to the operating system. The current process exits, and the OS spawns a new one with the same arguments. On macOS, the new process appears as if the app was freshly launched. On Linux and Windows, behavior is similar but depends on the desktop environment.

Exit vs Relaunch context:

exit is best used when the app must close after a critical error, or when the user triggers a "Quit" action you want to handle programmatically. relaunch is useful when your app changes its own configuration and needs a fresh start to apply settings—like language changes or theme overrides that only take effect at launch.

Permissions

Tauri v2 enforces a strict security model where every plugin command is denied by default. You must explicitly grant permissions for the operations you need. That model is covered in Permissions & Security.

Add the following to your capability file, usually src-tauri/capabilities/default.json:

{
  "identifier": "default",
  "windows": ["main"],
  "permissions": [
    "core:default",
    "process:default"
  ]
}

The process:default permission set includes both allow-exit and allow-restart. That’s enough for most applications.

If you need more granular control, you can grant individual permissions:

{
  "permissions": [
    "process:allow-exit",
    "process:allow-restart"
  ]
}
IdentifierDescription
process:allow-exitEnables the exit command.
process:deny-exitDenies the exit command (default).
process:allow-restartEnables the restart/relaunch command.
process:deny-restartDenies the restart/relaunch command (default).

Missing permissions cause runtime errors:

If you call exit or relaunch without granting the corresponding permission, Tauri will throw an error at runtime. The app will not crash silently—it will fail with a permission denied message. Always test your capability configuration early.

Managing Processes

Controlling an app’s lifecycle from code might seem trivial, but it interacts with operating system conventions in subtle ways. The two main actions—exit and relaunch—are not just "stop" and "start again." They carry state and expectations. Managing Processes goes deeper on exit codes, relaunch, and cleanup.

Exiting with a Status Code

Every process returns an integer to the operating system when it finishes. Conventionally, 0 means success; anything else signals an error. The exit function lets you set this code deliberately.

await exit(0);   // clean exit
await exit(1);   // indicates a problem

When you exit with a non-zero code, external scripts or process managers can detect that something went wrong. This is especially important if your Tauri app is launched by an installer, a CI pipeline, or a parent process that waits for the exit status.

When a non-zero exit code matters:

If your app performs a one-time task (like a migration tool) and exits, use exit(0) on success and exit(1) on failure. The calling environment can then decide what to do next. For a typical GUI app that the user closes, a zero exit code is fine.

A common beginner mistake is calling exit in the middle of a long-running operation expecting the app to stop gracefully. exit is immediate—it does not wait for pending I/O, network requests, or state cleanup. If you need to finish work before quitting, do that work first, then call exit.

// ❌ This may lose data
await saveData();   // might not finish before exit
await exit(0);
// ✅ Save, wait, then exit
await saveData();
// Optional: brief delay to let OS flush buffers
setTimeout(() => exit(0), 100);

Relaunching the Application

Relaunch is more complex than exit because it involves two transitions: the current process dying, and a new one being born. When you call relaunch(), the plugin:

  1. Tells the operating system to start a new instance of the app.
  2. Terminates the current process.

The new instance does not inherit any in-memory state from the old one. All variables, Redux stores, React component state, and Rust state are gone. The new instance starts with the same command-line arguments as the original.

Data loss risk on relaunch:

Because relaunch kills the process, unsaved data will be lost just like with exit. Save everything you need before calling relaunch. Use the plugin’s own lifecycle hooks (or Tauri’s on_event) to persist state before the shutdown.

Relaunch is ideal when your application alters its own configuration file and needs the changes to take effect. For example, after the user switches the app language:

import { relaunch } from '@tauri-apps/plugin-process';
import { writeTextFile } from '@tauri-apps/plugin-fs';
async function applyLanguage(lang: string) {
  // Save language preference to a config file
  await writeTextFile('config.json', JSON.stringify({ language: lang }));
  // Restart to load the new language
  await relaunch();
}

Relaunch may behave differently across platforms:

On macOS, the new instance appears as a separate launch event. On Linux, some desktop environments may treat the restart as a window close followed by a new window, which can trigger session management features. Always test relaunch behavior on your target operating systems.

Restart from Rust

The Rust API offers app.restart(). Under the hood, it uses Tauri’s built-in request_restart mechanism, which handles platform-specific details. Use it when you are deep in backend logic and need to restart without round-tripping to JavaScript.

// Example: restart after applying a critical update
app.restart();

The same data-loss caveats apply: save everything first. You can hook into Tauri’s RunEvent::Exit to persist state just before exit, whether it came from exit or restart.

use tauri::RunEvent;
tauri::Builder::default()
    .plugin(tauri_plugin_process::init())
    .build(tauri::generate_context!())
    .expect("error")
    .run(|_app, event| {
        if let RunEvent::Exit = event {
            // Cleanup code: flush caches, close handles
        }
    });

Lifecycle hooks work with both APIs:

Tauri’s RunEvent::Exit fires regardless of whether the exit originated from JavaScript exit, JavaScript relaunch, or Rust restart. Use it as a single cleanup point.

Common Mistakes

  • Forgetting permissions — the most frequent error. Check capabilities before assuming the functions will work.
  • Assuming code after exit runs — it usually won’t. Treat exit() as the last line of code that executes.
  • Confusing relaunch with a soft refresh — it’s a full process restart, not an in-place page reload. Use window.location.reload() for a simple frontend refresh.
  • Calling exit with the wrong status code — pick 0 for success, non-zero for failures, and document what each code means if your app is scripted.

Summary

The Process Plugin handles two fundamental yet delicate operations: stopping your app and starting it again. exit gives you control over the termination status, which is critical when your app is part of a larger automated workflow. relaunch allows a full reset of the application state without manual user intervention.

Introduction to the Process Plugin

Understand what the Tauri Process Plugin is, why it is needed, and the real-world scenarios where controlling your app's own process from the frontend becomes essential.

Managing Processes

Learn to control your Tauri application lifecycle by exiting, restarting, and accessing process metadata from a React frontend