# Tauri app Full Documentation Tauri is a framework for building tiny, fast binaries for all major desktop and mobile platforms. Developers can integrate any frontend framework that compiles to HTML, JavaScript, and CSS for building their user experience while leveraging languages such as Rust, Swift, and Kotlin for backend logic when needed. **Table of Contents** 1. Start - [What is Tauri?](#start) - [Create a Project](#start/create-project) - [Frontend Configuration](#start/frontend) - [Leptos](#start/frontend/leptos) - [Next.js](#start/frontend/nextjs) - [Nuxt](#start/frontend/nuxt) - [Qwik](#start/frontend/qwik) - [SvelteKit](#start/frontend/sveltekit) - [Trunk](#start/frontend/trunk) - [Vite](#start/frontend/vite) - [Upgrade & Migrate](#start/migrate) - [Upgrade from Tauri 1.0](#start/migrate/from-tauri-1) - [Upgrade from Tauri 2.0 Beta](#start/migrate/from-tauri-2-beta) - [Prerequisites](#start/prerequisites) 2. Concept - [Core Concepts](#concept) - [Tauri Architecture](#concept/architecture) - [Inter-Process Communication](#concept/inter-process-communication) - [Brownfield Pattern](#concept/inter-process-communication/brownfield) - [Isolation Pattern](#concept/inter-process-communication/isolation) - [Process Model](#concept/process-model) - [App Size](#concept/size) 3. Security - [Security](#security) - [Capabilities](#security/capabilities) - [Content Security Policy (CSP)](#security/csp) - [Tauri Ecosystem Security](#security/ecosystem) - [Future Work](#security/future) - [HTTP Headers](#security/http-headers) - [Application Lifecycle Threats](#security/lifecycle) - [Permissions](#security/permissions) - [Runtime Authority](#security/runtime-authority) - [Command Scopes](#security/scope) 4. Develop - [Develop](#develop) - [Calling the Frontend from Rust](#develop/calling-frontend) - [Calling Rust from the Frontend](#develop/calling-rust) - [Configuration Files](#develop/configuration-files) - [Debug](#develop/debug) - [CrabNebula DevTools](#develop/debug/crabnebula-devtools) - [Debug in Neovim](#develop/debug/neovim) - [Debug in JetBrains IDEs](#develop/debug/rustrover) - [Debug in VS Code](#develop/debug/vscode) - [Plugin Development](#develop/plugins) - [Mobile Plugin Development](#develop/plugins/develop-mobile) - [Embedding Additional Files](#develop/resources) - [Embedding External Binaries](#develop/sidecar) - [State Management](#develop/state-management) - [Tests](#develop/tests) - [Mock Tauri APIs](#develop/tests/mocking) - [WebDriver](#develop/tests/webdriver) - [Continuous Integration](#develop/tests/webdriver/ci) - [Setup](#develop/tests/webdriver/example) - [Selenium](#develop/tests/webdriver/example/selenium) - [WebdriverIO](#develop/tests/webdriver/example/webdriverio) - [Updating Dependencies](#develop/updating-dependencies) 5. Distribute - [Distribute](#distribute) - [App Store](#distribute/app-store) - [AppImage](#distribute/appimage) - [AUR](#distribute/aur) - [Distributing with CrabNebula Cloud](#distribute/crabnebula-cloud) - [Debian](#distribute/debian) - [DMG](#distribute/dmg) - [Flathub](#distribute/flatpak) - [Google Play](#distribute/google-play) - [macOS Application Bundle](#distribute/macos-application-bundle) - [Microsoft Store](#distribute/microsoft-store) - [CrabNebula Cloud](#distribute/pipelines/crabnebula-cloud) - [GitHub](#distribute/pipelines/github) - [RPM](#distribute/rpm) - [Android Code Signing](#distribute/sign/android) - [iOS Code Signing](#distribute/sign/ios) - [Linux Code Signing](#distribute/sign/linux) - [macOS Code Signing](#distribute/sign/macos) - [Windows Code Signing](#distribute/sign/windows) - [Snapcraft](#distribute/snapcraft) - [Windows Installer](#distribute/windows-installer) 6. Learn - [Learn](#learn) - [Capabilities for Different Windows and Platforms](#learn/security/capabilities-for-windows-and-platforms) - [Using Plugin Permissions](#learn/security/using-plugin-permissions) - [Writing Plugin Permissions](#learn/security/writing-plugin-permissions) - [Node.js as a sidecar](#learn/sidecar-nodejs) - [Splashscreen](#learn/splashscreen) - [System Tray](#learn/system-tray) - [Window Customization](#learn/window-customization) - [Window Menu](#learn/window-menu) # Start # What is Tauri? Tauri is a framework for building tiny, fast binaries for all major desktop and mobile platforms. Developers can integrate any frontend framework that compiles to HTML, JavaScript, and CSS for building their user experience while leveraging languages such as Rust, Swift, and Kotlin for backend logic when needed. Get started building with [`create-tauri-app`](https://github.com/tauri-apps/create-tauri-app) by using one of the below commands. Be sure to follow the [prerequisites guide](/start/prerequisites/) to install all of the dependencies required by Tauri and then view the [Frontend Configuration guides](/start/frontend/) for recommended frontend configurations. import Cta from '../_fragments/cta.mdx'; After you've created your first app you can explore the different features and recipes of Tauri in the [List of Features & Recipes](/plugin/). ## Why Tauri? Tauri has 3 main advantages for developers to build upon: - Secure foundation for building apps - Smaller bundle size by using the system's native webview - Flexibility for developers to use any frontend and bindings for multiple languages Learn more about the Tauri philosophy in the [Tauri 1.0 blog post](/blog/tauri-1-0/). ### Secure Foundation By being built on Rust, Tauri is able to take advantage of the memory, thread, and type-safety offered by Rust. Apps built on Tauri can automatically get those benefits even without needing to be developed by Rust experts. Tauri also undergoes a security audit for major and minor releases. This not only covers code in the Tauri organization, but also for upstream dependencies that Tauri relies on. Of course this doesn't mitigate all risks, but it provides a solid foundation for developers to build on top of. Read the [Tauri security policy](https://github.com/tauri-apps/tauri/security/policy) and the [Tauri 2.0 audit report](https://github.com/tauri-apps/tauri/blob/dev/audits/Radically_Open_Security-v2-report.pdf). ### Smaller App Size Tauri apps take advantage of the web view already available on every user's system. A Tauri app only contains the code and assets specific for that app and doesn't need to bundle a browser engine with every app. This means that a minimal Tauri app can be less than 600KB in size. Learn more about creating optimized apps in the [App Size concept](/concept/size/). ### Flexible Architecture Since Tauri uses web technologies that means that virtually any frontend framework is compatible with Tauri. The [Frontend Configuration guide](/start/frontend/) contains common configurations for popular frontend frameworks. Bindings between JavaScript and Rust are available to developers using the `invoke` function in JavaScript and Swift and Kotlin bindings are available for [Tauri Plugins](/develop/plugins/). [TAO](https://github.com/tauri-apps/tao) is responsible for Tauri window creation and [WRY](https://github.com/tauri-apps/wry) is responsible for web view rendering. These are libraries maintained by Tauri and can be consumed directly if deeper system integration is required outside of what Tauri exposes. In addition, Tauri maintains a number of plugins to extend what core Tauri exposes. You can find those plugins alongside those provided by the community in the [Plugins section](/plugin/). # Create a Project import { Card, Steps } from '@astrojs/starlight/components'; import Cta from '@fragments/cta.mdx'; One thing that makes Tauri so flexible is its ability to work with virtually any frontend framework. We've created the [`create-tauri-app`](https://github.com/tauri-apps/create-tauri-app) utility to help you create a new Tauri project using one of the officially maintained framework templates. `create-tauri-app` currently includes templates for vanilla (HTML, CSS and JavaScript without a framework), [Vue.js](https://vuejs.org), [Svelte](https://svelte.dev), [React](https://reactjs.org/), [SolidJS](https://www.solidjs.com/), [Angular](https://angular.io/), [Preact](https://preactjs.com/), [Yew](https://yew.rs/), [Leptos](https://github.com/leptos-rs/leptos), and [Sycamore](https://sycamore-rs.netlify.app/). You can also find or add your own community templates and frameworks in the [Awesome Tauri repo](https://github.com/tauri-apps/awesome-tauri). {/* TODO: redirect to integrate to existing front-end project specific docs */} Alternatively, you can [add Tauri to an existing project](#manual-setup-tauri-cli) to quickly turn your existing codebase into a Tauri app. ## Using `create-tauri-app` To get started using `create-tauri-app` run one of the below commands in the folder you'd like to setup your project. If you're not sure which command to use we recommend the Bash command on Linux and macOS and the PowerShell command on Windows. Follow along with the prompts to choose your project name, frontend language, package manager, and frontend framework, and frontend framework options if applicable. :::tip[Not sure what to choose?] We recommend starting with the vanilla template (HTML, CSS, and JavaScript without a frontend framework) to get started. You can always [integrate a frontend framework](/start/frontend/) later. - Choose which language to use for your frontend: `TypeScript / JavaScript` - Choose your package manager: `pnpm` - Choose your UI template: `Vanilla` - Choose your UI flavor: `TypeScript` ::: #### Scaffold a new project 1. Choose a name and a bundle identifier (unique-id for your app): ``` ? Project name (tauri-app) › ? Identifier (com.tauri-app.app) › ``` 2. Select a flavor for your frontend. First the language: ``` ? Choose which language to use for your frontend › Rust (cargo) TypeScript / JavaScript (pnpm, yarn, npm, bun) .NET (dotnet) ``` 3. Select a package manager (if there are multiple available): Options for **TypeScript / JavaScript**: ``` ? Choose your package manager › pnpm yarn npm bun ``` 4. Select a UI Template and flavor (if there are multiple available): Options for **Rust**: ``` ? Choose your UI template › Vanilla Yew Leptos Sycamore ``` Options for **TypeScript / JavaScript**: ``` ? Choose your UI template › Vanilla Vue Svelte React Solid Angular Preact ? Choose your UI flavor › TypeScript JavaScript ``` Options for **.NET**: ``` ? Choose your UI template › Blazor (https://dotnet.microsoft.com/en-us/apps/aspnet/web-apps/blazor/) ``` Once completed, the utility reports that the template has been created and displays how to run it using the configured package manager. If it detects missing dependencies on your system, it prints a list of packages and prompts how to install them. {/* TODO: Can CTA offer to install the deps? */} #### Start the development server After `create-tauri-app` has complete you can navigate into your project's folder, install dependencies, then use the [Tauri CLI](/reference/cli/) to start the development server: import CommandTabs from '@components/CommandTabs.astro'; You'll now see a new window open with your app running. **Congratulations!** You've made your Tauri app! 🚀 ## Manual Setup (Tauri CLI) If you already have an existing frontend or prefer to set it up yourself, you can use the Tauri CLI to initialize the backend for your project separately. :::note The following example assumes you are creating a new project. If you've already initialized the frontend of your application, you can skip the first step. ::: 1. Create a new directory for your project and initialize the frontend. You can use plain HTML, CSS, and JavaScript, or any framework you prefer such as Next.js, Nuxt, Svelte, Yew, or Leptos. You just need a way of serving the app in your browser. Just as an example, this is how you would setup a simple Vite app: 2. Then, install Tauri's CLI tool using your package manager of choice. If you are using `cargo` to install the Tauri CLI, you will have to install it globally. 3. Determine the URL of your frontend development server. This is the URL that Tauri will use to load your content. For example, if you are using Vite, the default URL is `http://localhost:5173`. 4. In your project directory, initialize Tauri: After running the command it will display a prompt asking you for different options: ```sh frame=none ✔ What is your app name? tauri-app ✔ What should the window title be? tauri-app ✔ Where are your web assets located? .. ✔ What is the url of your dev server? http://localhost:5173 ✔ What is your frontend dev command? pnpm run dev ✔ What is your frontend build command? pnpm run build ``` This will create a `src-tauri` directory in your project with the necessary Tauri configuration files. 5. Verify your Tauri app is working by running the development server: This command will compile the Rust code and open a window with your web content. **Congratulations!** You've created a new Tauri project using the Tauri CLI! 🚀 ## Next Steps - [Add and Configure a Frontend Framework](/start/frontend/) - [Tauri Command Line Interface (CLI) Reference](/reference/cli/) - [Learn how to build your Tauri app](/develop/) - [Discover additional features to extend Tauri](/plugin/) # Frontend Configuration import { LinkCard, CardGrid } from '@astrojs/starlight/components'; Tauri is frontend agnostic and supports most frontend frameworks out of the box. However, sometimes a framework need a bit of extra configuration to integrate with Tauri. Below is a list of frameworks with recommended configurations. If a framework is not listed then it may work with Tauri with no additional configuration needed or it could have not been documented yet. Any contributions to add a framework that may require additional configuration are welcome to help others in the Tauri community. ## Configuration Checklist Conceptually Tauri acts as a static web host. You need to provide Tauri with a folder containing some mix of HTML, CSS, Javascript and possibly WASM that can be served to the webview Tauri provides. Below is a checklist of common scenarios needed to integrate a frontend with Tauri: {/* TODO: Link to core concept of SSG/SSR, etc. */} {/* TODO: Link to mobile development server guide */} {/* TODO: Concept of how to do a client-server relationship? */} - Use static site generation (SSG), single-page applications (SPA), or classic multi-page apps (MPA). Tauri does not natively support server based alternatives (such as SSR). - For mobile development, a development server of some kind is necessary that can host the frontend on your internal IP. - Use a proper client-server relationship between your app and your API's (no hybrid solutions with SSR). ## JavaScript {/* TODO: Help me with the wording here lol */} For most projects we recommend [Vite](https://vitejs.dev/) for SPA frameworks such as React, Vue, Svelte, and Solid, but also for plain JavaScript or TypeScript projects. Most other guides listed here show how to use Meta-Frameworks as they are typically designed for SSR and therefore require special configuration. ## Rust
:::tip[Framework Not Listed?] Don't see a framework listed? It may work with Tauri without any additional configuration required. Read the [configuration checklist](/start/frontend/#configuration-checklist) for any common configurations to check for. ::: # Leptos import { Tabs, TabItem, Steps } from '@astrojs/starlight/components'; import CommandTabs from '@components/CommandTabs.astro'; Leptos is a Rust based web framework. You can read more about Leptos on their [official website](https://leptos.dev/). This guide is accurate as of Leptos version 0.6. ## Checklist - Use SSG, Tauri doesn't officially support server based solutions. - Use `serve.ws_protocol = "ws"` so that the hot-reload websocket can connect properly for mobile development. - Enable `withGlobalTauri` to ensure that Tauri APIs are available in the `window.__TAURI__` variable and can be imported using `wasm-bindgen`. ## Example Configuration 1. ##### Update Tauri configuration ```json // src-tauri/tauri.conf.json { "build": { "beforeDevCommand": "trunk serve", "devUrl": "http://localhost:1420", "beforeBuildCommand": "trunk build", "frontendDist": "../dist" }, "app": { "withGlobalTauri": true } } ``` 1. ##### Update Trunk configuration ```toml // Trunk.toml [build] target = "./index.html" [watch] ignore = ["./src-tauri"] [serve] port = 1420 open = false ws_protocol = "ws" ``` # Next.js import { Tabs, TabItem, Steps } from '@astrojs/starlight/components'; import CommandTabs from '@components/CommandTabs.astro'; Next.js is a meta framework for React. Learn more about Next.js at https://nextjs.org. This guide is accurate as of Next.js 14.2.3. ## Checklist - Use static exports by setting `output: 'export'`. Tauri doesn't support server-based solutions. - Use the `out` directory as `frontendDist` in `tauri.conf.json`. ## Example Configuration 1. ##### Update Tauri configuration ```json // src-tauri/tauri.conf.json { "build": { "beforeDevCommand": "npm run dev", "beforeBuildCommand": "npm run build", "devUrl": "http://localhost:3000", "frontendDist": "../out" } } ``` ```json // src-tauri/tauri.conf.json { "build": { "beforeDevCommand": "yarn dev", "beforeBuildCommand": "yarn build", "devUrl": "http://localhost:3000", "frontendDist": "../out" } } ``` ```json // src-tauri/tauri.conf.json { "build": { "beforeDevCommand": "pnpm dev", "beforeBuildCommand": "pnpm build", "devUrl": "http://localhost:3000", "frontendDist": "../out" } } ``` ```json // src-tauri/tauri.conf.json { "build": { "beforeDevCommand": "deno task dev", "beforeBuildCommand": "deno task build", "devUrl": "http://localhost:3000", "frontendDist": "../out" } } ``` 2. ##### Update Next.js configuration ```ts // next.conf.mjs const isProd = process.env.NODE_ENV === 'production'; const internalHost = process.env.TAURI_DEV_HOST || 'localhost'; /** @type {import('next').NextConfig} */ const nextConfig = { // Ensure Next.js uses SSG instead of SSR // https://nextjs.org/docs/pages/building-your-application/deploying/static-exports output: 'export', // Note: This feature is required to use the Next.js Image component in SSG mode. // See https://nextjs.org/docs/messages/export-image-api for different workarounds. images: { unoptimized: true, }, // Configure assetPrefix or else the server won't properly resolve your assets. assetPrefix: isProd ? undefined : `http://${internalHost}:3000`, }; export default nextConfig; ``` 3. ##### Update package.json configuration ```json "scripts": { "dev": "next dev", "build": "next build", "start": "next start", "lint": "next lint", "tauri": "tauri" } ``` # Nuxt import { Tabs, TabItem, Steps } from '@astrojs/starlight/components'; Nuxt is a meta framework for Vue. Learn more about Nuxt at https://nuxt.com. This guide is accurate as of Nuxt 3.11. ## Checklist - Use SSG by setting `ssr: false`. Tauri doesn't support server based solutions. - Use `process.env.TAURI_DEV_HOST` as the development server host IP when set to run on iOS physical devices. - Use `dist/` as `frontendDist` in `tauri.conf.json`. - Compile using `nuxi generate`. - (Optional): Disable telemetry by setting `telemetry: false` in `nuxt.config.ts`. ## Example Configuration 1. ##### Update Tauri configuration ```json // tauri.conf.json { "build": { "beforeDevCommand": "npm run dev", "beforeBuildCommand": "npm run generate", "devUrl": "http://localhost:3000", "frontendDist": "../dist" } } ``` ```json // tauri.conf.json { "build": { "beforeDevCommand": "yarn dev", "beforeBuildCommand": "yarn generate", "devUrl": "http://localhost:3000", "frontendDist": "../dist" } } ``` ```json // tauri.conf.json { "build": { "beforeDevCommand": "pnpm dev", "beforeBuildCommand": "pnpm generate", "devUrl": "http://localhost:3000", "frontendDist": "../dist" } } ``` ```json // tauri.conf.json { "build": { "beforeDevCommand": "deno task dev", "beforeBuildCommand": "deno task generate", "devUrl": "http://localhost:3000", "frontendDist": "../dist" } } ``` 1. ##### Update Nuxt configuration ```ts export default defineNuxtConfig({ // (optional) Enable the Nuxt devtools devtools: { enabled: true }, // Enable SSG ssr: false, // Enables the development server to be discoverable by other devices when running on iOS physical devices devServer: { host: process.env.TAURI_DEV_HOST || 'localhost' }, vite: { // Better support for Tauri CLI output clearScreen: false, // Enable environment variables // Additional environment variables can be found at // https://v2.tauri.app/reference/environment-variables/ envPrefix: ['VITE_', 'TAURI_'], server: { // Tauri requires a consistent port strictPort: true, }, }, }); ``` # Qwik import { Steps, TabItem, Tabs } from '@astrojs/starlight/components'; import CommandTabs from '@components/CommandTabs.astro'; This guide will walk you through creating your Tauri app using the Qwik web framework. Learn more about Qwik at https://qwik.dev. ## Checklist - Use [SSG](https://qwik.dev/docs/guides/static-site-generation/). Tauri doesn't support server-based solutions. - Use `dist/` as `frontendDist` in `tauri.conf.json`. ## Example Configuration 1. ##### Create a new Qwik app `} yarn={`yarn create qwik@latest cd `} pnpm={`pnpm create qwik@latest cd `} deno={`deno run -A npm:create-qwik@latest cd `} /> 1. ##### Install the `static adapter` 1. ##### Add the Tauri CLI to your project 1. ##### Initiate a new Tauri project 1. ##### Tauri configuration ```json // tauri.conf.json { "build": { "devUrl": "http://localhost:5173" "frontendDist": "../dist", "beforeDevCommand": "npm run dev", "beforeBuildCommand": "npm run build" } } ``` ```json // tauri.conf.json { "build": { "devUrl": "http://localhost:5173" "frontendDist": "../dist", "beforeDevCommand": "yarn dev", "beforeBuildCommand": "yarn build" } } ``` ```json // tauri.conf.json { "build": { "devUrl": "http://localhost:5173" "frontendDist": "../dist", "beforeDevCommand": "pnpm dev", "beforeBuildCommand": "pnpm build" } } ``` ```json // tauri.conf.json { "build": { "devUrl": "http://localhost:5173" "frontendDist": "../dist", "beforeDevCommand": "deno task dev", "beforeBuildCommand": "deno task build" } } ``` 1. ##### Start your `tauri` app # SvelteKit import { Tabs, TabItem, Steps } from '@astrojs/starlight/components'; import CommandTabs from '@components/CommandTabs.astro'; SvelteKit is a meta framework for Svelte. Learn more about SvelteKit at https://kit.svelte.dev/. This guide is accurate as of SvelteKit 2.20.4 / Svelte 5.25.8. ## Checklist - Use [SSG](https://kit.svelte.dev/docs/adapter-static) and [SPA](https://svelte.dev/docs/kit/single-page-apps) via `static-adapter`. Tauri doesn't support server-based solutions. - If using SSG **with prerendering**, be aware that `load` functions will not have access to tauri APIs during the build process of your app. Using SPA mode (without prerendering) is recommended since the load functions will only run in the webview with access to tauri APIs. - Use `build/` as `frontendDist` in `tauri.conf.json`. ## Example Configuration 1. ##### Install `@sveltejs/adapter-static` 1. ##### Update Tauri configuration ```json // tauri.conf.json { "build": { "beforeDevCommand": "npm run dev", "beforeBuildCommand": "npm run build", "devUrl": "http://localhost:5173", "frontendDist": "../build" } } ``` ```json // tauri.conf.json { "build": { "beforeDevCommand": "yarn dev", "beforeBuildCommand": "yarn build", "devUrl": "http://localhost:5173", "frontendDist": "../build" } } ``` ```json // tauri.conf.json { "build": { "beforeDevCommand": "pnpm dev", "beforeBuildCommand": "pnpm build", "devUrl": "http://localhost:5173", "frontendDist": "../build" } } ``` ```json // tauri.conf.json { "build": { "beforeDevCommand": "deno task dev", "beforeBuildCommand": "deno task build", "devUrl": "http://localhost:5173", "frontendDist": "../build" } } ``` 1. ##### Update SvelteKit configuration: ```js title="svelte.config.js" {1} import adapter from '@sveltejs/adapter-static'; import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'; /** @type {import('@sveltejs/kit').Config} */ const config = { // Consult https://kit.svelte.dev/docs/integrations#preprocessors // for more information about preprocessors preprocess: vitePreprocess(), kit: { adapter: adapter({ fallback: 'index.html', }), }, }; export default config; ``` 1. ##### Disable SSR Lastly, we need to disable SSR by adding a root `+layout.ts` file (or `+layout.js` if you are not using TypeScript) with these contents: ```ts // src/routes/+layout.ts export const ssr = false; ``` Note that `static-adapter` doesn't require you to disable SSR for the whole app but it makes it possible to use APIs that depend on the global window object (like Tauri's API) without [Client-side checks](https://kit.svelte.dev/docs/faq#how-do-i-use-x-with-sveltekit-how-do-i-use-a-client-side-only-library-that-depends-on-document-or-window). Furthermore, if you prefer Static Site Generation (SSG) over Single-Page Application (SPA) mode, you can change the adapter configurations and `+layout.ts` according to the [adapter docs](https://svelte.dev/docs/kit/adapter-static). # Trunk import { Tabs, TabItem, Steps } from '@astrojs/starlight/components'; Trunk is a WASM web application bundler for Rust. Learn more about Trunk at https://trunkrs.dev. This guide is accurate as of Trunk 0.17.5. ## Checklist - Use SSG, Tauri doesn't officially support server based solutions. - Use `serve.ws_protocol = "ws"` so that the hot-reload websocket can connect properly for mobile development. - Enable `withGlobalTauri` to ensure that Tauri APIs are available in the `window.__TAURI__` variable and can be imported using `wasm-bindgen`. ## Example Configuration 1. ##### Update Tauri configuration ```json // tauri.conf.json { "build": { "beforeDevCommand": "trunk serve", "beforeBuildCommand": "trunk build", "devUrl": "http://localhost:8080", "frontendDist": "../dist" }, "app": { "withGlobalTauri": true } } ``` 1. ##### Update Trunk configuration ```toml # Trunk.toml [watch] ignore = ["./src-tauri"] [serve] ws_protocol = "ws" ``` # Vite import { Tabs, TabItem, Steps } from '@astrojs/starlight/components'; Vite is a build tool that aims to provide a faster and leaner development experience for modern web projects. This guide is accurate as of Vite 5.4.8. ## Checklist - Use `../dist` as `frontendDist` in `src-tauri/tauri.conf.json`. - Use `process.env.TAURI_DEV_HOST` as the development server host IP when set to run on iOS physical devices. ## Example configuration 1. ##### Update Tauri configuration Assuming you have the following `dev` and `build` scripts in your `package.json`: ```json { "scripts": { "dev": "vite", "build": "tsc && vite build", "preview": "vite preview", "tauri": "tauri" } } ``` You can configure the Tauri CLI to use your Vite development server and dist folder along with the hooks to automatically run the Vite scripts: ```json // tauri.conf.json { "build": { "beforeDevCommand": "npm run dev", "beforeBuildCommand": "npm run build", "devUrl": "http://localhost:5173", "frontendDist": "../dist" } } ``` ```json // tauri.conf.json { "build": { "beforeDevCommand": "yarn dev", "beforeBuildCommand": "yarn build", "devUrl": "http://localhost:5173", "frontendDist": "../dist" } } ``` ```json // tauri.conf.json { "build": { "beforeDevCommand": "pnpm dev", "beforeBuildCommand": "pnpm build", "devUrl": "http://localhost:5173", "frontendDist": "../dist" } } ``` ```json // tauri.conf.json { "build": { "beforeDevCommand": "deno task dev", "beforeBuildCommand": "deno task build", "devUrl": "http://localhost:5173", "frontendDist": "../dist" } } ``` 1. ##### Update Vite configuration: ```js title="vite.config.js" import { defineConfig } from 'vite'; const host = process.env.TAURI_DEV_HOST; export default defineConfig({ // prevent vite from obscuring rust errors clearScreen: false, server: { port: 1420, // Tauri expects a fixed port, fail if that port is not available strictPort: true, // if the host Tauri is expecting is set, use it host: host || false, hmr: host ? { protocol: 'ws', host, port: 1421, } : undefined, watch: { // tell vite to ignore watching `src-tauri` ignored: ['**/src-tauri/**'], }, }, // Env variables starting with the item of `envPrefix` will be exposed in tauri's source code through `import.meta.env`. envPrefix: ['VITE_', 'TAURI_ENV_*'], build: { // Tauri uses Chromium on Windows and WebKit on macOS and Linux target: process.env.TAURI_ENV_PLATFORM == 'windows' ? 'chrome105' : 'safari13', // don't minify for debug builds minify: !process.env.TAURI_ENV_DEBUG ? 'esbuild' : false, // produce sourcemaps for debug builds sourcemap: !!process.env.TAURI_ENV_DEBUG, }, }); ``` # Upgrade & Migrate Learn about common scenarios and steps to upgrade from Tauri 1.0 or migrate from another framework. import { LinkCard, CardGrid } from '@astrojs/starlight/components'; # Upgrade from Tauri 1.0 import { Tabs, TabItem } from '@astrojs/starlight/components'; import CommandTabs from '@components/CommandTabs.astro'; This guide walks you through upgrading your Tauri 1.0 application to Tauri 2.0. ## Preparing for Mobile The mobile interface of Tauri requires your project to output a shared library. If you are targeting mobile for your existing application, you must change your crate to produce that kind of artifact along with the desktop executable. 1. Change the Cargo manifest to produce the library. Append the following block: ```toml // src-tauri/Cargo.toml [lib] name = "app_lib" crate-type = ["staticlib", "cdylib", "rlib"] ``` 2. Rename `src-tauri/src/main.rs` to `src-tauri/src/lib.rs`. This file will be shared by both desktop and mobile targets. 3. Rename the `main` function header in `lib.rs` to the following: ```rust // src-tauri/src/lib.rs #[cfg_attr(mobile, tauri::mobile_entry_point)] pub fn run() { // your code here } ``` The `tauri::mobile_entry_point` macro prepares your function to be executed on mobile. 4. Recreate the `main.rs` file calling the shared run function: ```rust // src-tauri/src/main.rs #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] fn main() { app_lib::run(); } ``` ## Automated Migration :::danger This command is not a substitude for this guide! Please read the _whole_ page regardless of whether you chose to use the command. ::: The Tauri v2 CLI includes a `migrate` command that automates most of the process and helps you finish the migration: Learn more about the `migrate` command in the [Command Line Interface reference](/reference/cli/#migrate) ## Summary of Changes Below is a summary of the changes from Tauri 1.0 to Tauri 2.0: ### Tauri Configuration - `package > productName` and `package > version` moved to top-level object. - the binary name is no longer renamed to match `productName` automatically, so you must add a `mainBinaryName` string to the top-level object matching `productName`. - `package` removed. - `tauri` key renamed to `app`. - `tauri > allowlist` removed. Refer to [Migrate Permissions](#migrate-permissions). - `tauri > allowlist > protocol > assetScope` moved to `app > security > assetProtocol > scope`. - `tauri > cli` moved to `plugins > cli`. - `tauri > windows > fileDropEnabled` renamed to `app > windows > dragDropEnabled`. - `tauri > updater > active` removed. - `tauri > updater > dialog` removed. - `tauri > updater` moved to `plugins > updater`. - `bundle > createUpdaterArtifacts` added, must be set when using the app updater. - set it to `v1Compatible` when upgrading from v1 apps that were already distributed. See the [updater guide](/plugin/updater/) for more information. - `tauri > systemTray` renamed to `app > trayIcon`. - `tauri > pattern` moved to `app > security > pattern`. - `tauri > bundle` moved top-level. - `tauri > bundle > identifier` moved to top-level object. - `tauri > bundle > dmg` moved to `bundle > macOS > dmg` - `tauri > bundle > deb` moved to `bundle > linux > deb` - `tauri > bundle > appimage` moved to `bundle > linux > appimage` - `tauri > bundle > macOS > license` removed, use `bundle > licenseFile` instead. - `tauri > bundle > windows > wix > license` removed, use `bundle > licenseFile` instead. - `tauri > bundle > windows > nsis > license` removed, use `bundle > licenseFile` instead. - `tauri > bundle > windows > webviewFixedRuntimePath` removed, use `bundle > windows > webviewInstallMode` instead. - `build > withGlobalTauri` moved to `app > withGlobalTauri`. - `build > distDir` renamed to `frontendDist`. - `build > devPath` renamed to `devUrl`. [Tauri 2.0 Configuration API reference](/reference/config/) ### New Cargo Features - linux-protocol-body: Enables custom protocol request body parsing, allowing the IPC to use it. Requires webkit2gtk 2.40. ### Removed Cargo Features - reqwest-client: reqwest is now the only supported client. - reqwest-native-tls-vendored: use `native-tls-vendored` instead. - process-command-api: use the `shell` plugin instead (see instructions in the following section). - shell-open-api: use the `shell` plugin instead (see instructions in the following section). - windows7-compat: moved to the `notification` plugin. - updater: Updater is now a plugin. - linux-protocol-headers: Now enabled by default since we upgraded our minimum webkit2gtk version. - system-tray: renamed to `tray-icon`. ### Rust Crate Changes - `api` module removed. Each API module can be found in a Tauri plugin. - `api::dialog` module removed. Use `tauri-plugin-dialog` instead. [Migration](#migrate-to-dialog-plugin) - `api::file` module removed. Use Rust's [`std::fs`](https://doc.rust-lang.org/std/fs/) instead. - `api::http` module removed. Use `tauri-plugin-http` instead. [Migration](#migrate-to-http-plugin) - `api::ip` module rewritten and moved to `tauri::ipc`. Check out the new APIs, specially `tauri::ipc::Channel`. - `api::path` module functions and `tauri::PathResolved` moved to `tauri::Manager::path`. [Migration](#migrate-path-to-tauri-manager) - `api::process::Command`, `tauri::api::shell` and `tauri::Manager::shell_scope` APIs removed. Use `tauri-plugin-shell` instead. [Migration](#migrate-to-shell-plugin) - `api::process::current_binary` and `tauri::api::process::restart` moved to `tauri::process`. - `api::version` module has been removed. Use the [semver crate](https://docs.rs/semver/latest/semver/) instead. - `App::clipboard_manager` and `AppHandle::clipboard_manager` removed. Use `tauri-plugin-clipboard` instead. [Migration](#migrate-to-clipboard-plugin) - `App::get_cli_matches` removed. Use `tauri-plugin-cli` instead. [Migration](#migrate-to-cli-plugin) - `App::global_shortcut_manager` and `AppHandle::global_shortcut_manager` removed. Use `tauri-plugin-global-shortcut` instead. [Migration](#migrate-to-global-shortcut-plugin) - `Manager::fs_scope` removed. The file system scope can be accessed via `tauri_plugin_fs::FsExt`. - `Plugin::PluginApi` now receives a plugin configuration as a second argument. - `Plugin::setup_with_config` removed. Use the updated `tauri::Plugin::PluginApi` instead. - `scope::ipc::RemoteDomainAccessScope::enable_tauri_api` and `scope::ipc::RemoteDomainAccessScope::enables_tauri_api` removed. Enable each core plugin individually via `scope::ipc::RemoteDomainAccessScope::add_plugin` instead. - `scope::IpcScope` removed, use `scope::ipc::Scope` instead. - `scope::FsScope`, `scope::GlobPattern` and `scope::FsScopeEvent` removed, use `scope::fs::Scope`, `scope::fs::Pattern` and `scope::fs::Event` respectively. - `updater` module removed. Use `tauri-plugin-updater` instead. [Migration](#migrate-to-updater-plugin) - `Env.args` field has been removed, use `Env.args_os` field instead. - `Menu`, `MenuEvent`, `CustomMenuItem`, `Submenu`, `WindowMenuEvent`, `MenuItem` and `Builder::on_menu_event` APIs removed. [Migration](#migrate-to-menu) - `SystemTray`, `SystemTrayHandle`, `SystemTrayMenu`, `SystemTrayMenuItemHandle`, `SystemTraySubmenu`, `MenuEntry` and `SystemTrayMenuItem` APIs removed. [Migration](#migrate-to-tray-icon-module) ### JavaScript API Changes The `@tauri-apps/api` package no longer provides non-core modules. Only the previous `tauri` (now `core`), `path`, `event` and `window` modules are exported. All others have been moved to plugins. - `@tauri-apps/api/tauri` module renamed to `@tauri-apps/api/core`. [Migration](#migrate-to-core-module) - `@tauri-apps/api/cli` module removed. Use `@tauri-apps/plugin-cli` instead. [Migration](#migrate-to-cli-plugin) - `@tauri-apps/api/clipboard` module removed. Use `@tauri-apps/plugin-clipboard` instead. [Migration](#migrate-to-clipboard-plugin) - `@tauri-apps/api/dialog` module removed. Use `@tauri-apps/plugin-dialog` instead. [Migration](#migrate-to-dialog-plugin) - `@tauri-apps/api/fs` module removed. Use `@tauri-apps/plugin-fs` instead. [Migration](#migrate-to-file-system-plugin) - `@tauri-apps/api/global-shortcut` module removed. Use `@tauri-apps/plugin-global-shortcut` instead. [Migration](#migrate-to-global-shortcut-plugin) - `@tauri-apps/api/http` module removed. Use `@tauri-apps/plugin-http` instead. [Migration](#migrate-to-http-plugin) - `@tauri-apps/api/os` module removed. Use `@tauri-apps/plugin-os` instead. [Migration](#migrate-to-os-plugin) - `@tauri-apps/api/notification` module removed. Use `@tauri-apps/plugin-notification` instead. [Migration](#migrate-to-notification-plugin) - `@tauri-apps/api/process` module removed. Use `@tauri-apps/plugin-process` instead. [Migration](#migrate-to-process-plugin) - `@tauri-apps/api/shell` module removed. Use `@tauri-apps/plugin-shell` instead. [Migration](#migrate-to-shell-plugin) - `@tauri-apps/api/updater` module removed. Use `@tauri-apps/plugin-updater` instead [Migration](#migrate-to-updater-plugin) - `@tauri-apps/api/window` module renamed to `@tauri-apps/api/webviewWindow`. [Migration](#migrate-to-new-window-api) The v1 plugins are now published as `@tauri-apps/plugin-`. Previously they were available from git as `tauri-plugin--api`. ### Environment Variables Changes Most of the environment variables read and written by the Tauri CLI were renamed for consistency and prevention of mistakes: - `TAURI_PRIVATE_KEY` -> `TAURI_SIGNING_PRIVATE_KEY` - `TAURI_KEY_PASSWORD` -> `TAURI_SIGNING_PRIVATE_KEY_PASSWORD` - `TAURI_SKIP_DEVSERVER_CHECK` -> `TAURI_CLI_NO_DEV_SERVER_WAIT` - `TAURI_DEV_SERVER_PORT` -> `TAURI_CLI_PORT` - `TAURI_PATH_DEPTH` -> `TAURI_CLI_CONFIG_DEPTH` - `TAURI_FIPS_COMPLIANT` -> `TAURI_BUNDLER_WIX_FIPS_COMPLIANT` - `TAURI_DEV_WATCHER_IGNORE_FILE` -> `TAURI_CLI_WATCHER_IGNORE_FILENAME` - `TAURI_TRAY` -> `TAURI_LINUX_AYATANA_APPINDICATOR` - `TAURI_APPLE_DEVELOPMENT_TEAM` -> `APPLE_DEVELOPMENT_TEAM` - `TAURI_PLATFORM` -> `TAURI_ENV_PLATFORM` - `TAURI_ARCH` -> `TAURI_ENV_ARCH` - `TAURI_FAMILY` -> `TAURI_ENV_FAMILY` - `TAURI_PLATFORM_VERSION` -> `TAURI_ENV_PLATFORM_VERSION` - `TAURI_PLATFORM_TYPE` -> `TAURI_ENV_PLATFORM_TYPE` - `TAURI_DEBUG` -> `TAURI_ENV_DEBUG` ### Event System The event system was redesigned to be easier to use. Instead of relying on the source of the event, it now has a simpler implementation that relies on event targets. - The `emit` function now emits the event to all event listeners. - Added a new `emit_to`/`emitTo` function to trigger an event to a specific target. - `emit_filter` now filters based on [`EventTarget`](https://docs.rs/tauri/2.0.0/tauri/event/enum.EventTarget.html) instead of a window. - Renamed `listen_global` to `listen_any`. It now listens to all events regardless of their filters and targets. - JavaScript: `event.listen()` behaves similar to `listen_any`. It now listens to all events regardless of their filters and targets, unless a target is set in the `Options`. - JavaScript: `WebviewWindow.listen` etc. only listen to events emitted to the respective `EventTarget`. ### Multiwebview support Tauri v2 introduces multiwebview support currently behind an `unstable` feature flag. In order to support it, we renamed the Rust `Window` type to `WebviewWindow` and the Manager `get_window` function to `get_webview_window`. The `WebviewWindow` JS API type is now re-exported from `@tauri-apps/api/webviewWindow` instead of `@tauri-apps/api/window`. ### New origin URL on Windows On Windows the frontend files in production apps are now hosted on `http://tauri.localhost` instead of `https://tauri.localhost`. Because of this IndexedDB, LocalStorage and Cookies will be reset unless `dangerousUseHttpScheme` was used in v1. To prevent this you can set `app > windows > useHttpsScheme` to `true` or use `WebviewWindowBuilder::use_https_scheme` to keep using the `https` scheme. ## Detailed Migration Steps Common scenarios you may encounter when migrating your Tauri 1.0 app to Tauri 2.0. ### Migrate to Core Module The `@tauri-apps/api/tauri` module was renamed to `@tauri-apps/api/core`. Simply rename the module import: ```diff - import { invoke } from "@tauri-apps/api/tauri" + import { invoke } from "@tauri-apps/api/core" ``` ### Migrate to CLI Plugin The Rust `App::get_cli_matches` JavaScript `@tauri-apps/api/cli` APIs have been removed. Use the `@tauri-apps/plugin-cli` plugin instead: 1. Add to cargo dependencies: ```toml # Cargo.toml [dependencies] tauri-plugin-cli = "2" ``` 2. Use in JavaScript or Rust project: ```rust fn main() { tauri::Builder::default() .plugin(tauri_plugin_cli::init()) } ``` ```json // package.json { "dependencies": { "@tauri-apps/plugin-cli": "^2.0.0" } } ``` ```javascript import { getMatches } from '@tauri-apps/plugin-cli'; const matches = await getMatches(); ``` ```rust fn main() { use tauri_plugin_cli::CliExt; tauri::Builder::default() .plugin(tauri_plugin_cli::init()) .setup(|app| { let cli_matches = app.cli().matches()?; Ok(()) }) } ``` ### Migrate to Clipboard Plugin The Rust `App::clipboard_manager` and `AppHandle::clipboard_manager` and JavaScript `@tauri-apps/api/clipboard` APIs have been removed. Use the `@tauri-apps/plugin-clipboard-manager` plugin instead: ```toml [dependencies] tauri-plugin-clipboard-manager = "2" ``` ```rust fn main() { tauri::Builder::default() .plugin(tauri_plugin_clipboard_manager::init()) } ``` ```json // package.json { "dependencies": { "@tauri-apps/plugin-clipboard-manager": "^2.0.0" } } ``` ```javascript import { writeText, readText } from '@tauri-apps/plugin-clipboard-manager'; await writeText('Tauri is awesome!'); assert(await readText(), 'Tauri is awesome!'); ``` ```rust use tauri_plugin_clipboard::{ClipboardExt, ClipKind}; tauri::Builder::default() .plugin(tauri_plugin_clipboard::init()) .setup(|app| { app.clipboard().write(ClipKind::PlainText { label: None, text: "Tauri is awesome!".into(), })?; Ok(()) }) ``` ### Migrate to Dialog Plugin The Rust `tauri::api::dialog` JavaScript `@tauri-apps/api/dialog` APIs have been removed. Use the `@tauri-apps/plugin-dialog` plugin instead: 1. Add to cargo dependencies: ```toml # Cargo.toml [dependencies] tauri-plugin-dialog = "2" ``` 2. Use in JavaScript or Rust project: ```rust fn main() { tauri::Builder::default() .plugin(tauri_plugin_dialog::init()) } ``` ```json // package.json { "dependencies": { "@tauri-apps/plugin-dialog": "^2.0.0" } } ``` ```javascript import { save } from '@tauri-apps/plugin-dialog'; const filePath = await save({ filters: [ { name: 'Image', extensions: ['png', 'jpeg'], }, ], }); ``` ```rust use tauri_plugin_dialog::DialogExt; tauri::Builder::default() .plugin(tauri_plugin_dialog::init()) .setup(|app| { app.dialog().file().pick_file(|file_path| { // do something with the optional file path here // the file path is `None` if the user closed the dialog }); app.dialog().message("Tauri is Awesome!").show(); Ok(()) }) ``` ### Migrate to File System Plugin The Rust `App::get_cli_matches` JavaScript `@tauri-apps/api/fs` APIs have been removed. Use the [`std::fs`](https://doc.rust-lang.org/std/fs/) for Rust and `@tauri-apps/plugin-fs` plugin for JavaScript instead: 1. Add to cargo dependencies: ```toml # Cargo.toml [dependencies] tauri-plugin-fs = "2" ``` 2. Use in JavaScript or Rust project: ```rust fn main() { tauri::Builder::default() .plugin(tauri_plugin_fs::init()) } ``` ```json // package.json { "dependencies": { "@tauri-apps/plugin-fs": "^2.0.0" } } ``` ```javascript import { mkdir, BaseDirectory } from '@tauri-apps/plugin-fs'; await mkdir('db', { baseDir: BaseDirectory.AppLocalData }); ``` Some functions and types have been renamed or removed: - `Dir` enum alias removed, use `BaseDirectory`. - `FileEntry`, `FsBinaryFileOption`, `FsDirOptions`, `FsOptions`, `FsTextFileOption` and `BinaryFileContents` interfaces and type aliases have been removed and replaced with new interfaces suited for each function. - `createDir` renamed to `mkdir`. - `readBinaryFile` renamed to `readFile`. - `removeDir` removed and replaced with `remove`. - `removeFile` removed and replaced with `remove`. - `renameFile` removed and replaced with `rename`. - `writeBinaryFile` renamed to `writeFile`. Use the Rust [`std::fs`](https://doc.rust-lang.org/std/fs/) functions. ### Migrate to Global Shortcut Plugin The Rust `App::global_shortcut_manager` and `AppHandle::global_shortcut_manager` and JavaScript `@tauri-apps/api/global-shortcut` APIs have been removed. Use the `@tauri-apps/plugin-global-shortcut` plugin instead: 1. Add to cargo dependencies: ```toml # Cargo.toml [dependencies] [target."cfg(not(any(target_os = \"android\", target_os = \"ios\")))".dependencies] tauri-plugin-global-shortcut = "2" ``` 2. Use in JavaScript or Rust project: ```rust fn main() { tauri::Builder::default() .plugin(tauri_plugin_global_shortcut::Builder::default().build()) } ``` ```json // package.json { "dependencies": { "@tauri-apps/plugin-global-shortcut": "^2.0.0" } } ``` ```javascript import { register } from '@tauri-apps/plugin-global-shortcut'; await register('CommandOrControl+Shift+C', () => { console.log('Shortcut triggered'); }); ``` ```rust use tauri_plugin_global_shortcut::GlobalShortcutExt; tauri::Builder::default() .plugin( tauri_plugin_global_shortcut::Builder::new().with_handler(|app, shortcut| { println!("Shortcut triggered: {:?}", shortcut); }) .build(), ) .setup(|app| { // register a global shortcut // on macOS, the Cmd key is used // on Windows and Linux, the Ctrl key is used app.global_shortcut().register("CmdOrCtrl+Y")?; Ok(()) }) ``` ### Migrate to HTTP Plugin The Rust `tauri::api::http` JavaScript `@tauri-apps/api/http` APIs have been removed. Use the `@tauri-apps/plugin-http` plugin instead: 1. Add to cargo dependencies: ```toml # Cargo.toml [dependencies] tauri-plugin-http = "2" ``` 2. Use in JavaScript or Rust project: ```rust fn main() { tauri::Builder::default() .plugin(tauri_plugin_http::init()) } ``` ```json // package.json { "dependencies": { "@tauri-apps/plugin-http": "^2.0.0" } } ``` ```javascript import { fetch } from '@tauri-apps/plugin-http'; const response = await fetch( 'https://raw.githubusercontent.com/tauri-apps/tauri/dev/package.json' ); ``` ```rust use tauri_plugin_http::reqwest; tauri::Builder::default() .plugin(tauri_plugin_http::init()) .setup(|app| { let response_data = tauri::async_runtime::block_on(async { let response = reqwest::get( "https://raw.githubusercontent.com/tauri-apps/tauri/dev/package.json", ) .await .unwrap(); response.text().await })?; Ok(()) }) ``` The HTTP plugin re-exports [reqwest](https://docs.rs/reqwest/latest/reqwest/) so you can check out their documentation for more information. ### Migrate to Notification Plugin The Rust `tauri::api::notification` JavaScript `@tauri-apps/api/notification` APIs have been removed. Use the `@tauri-apps/plugin-notification` plugin instead: 1. Add to cargo dependencies: ```toml # Cargo.toml [dependencies] tauri-plugin-notification = "2" ``` 2. Use in JavaScript or Rust project: ```rust fn main() { tauri::Builder::default() .plugin(tauri_plugin_notification::init()) } ``` ```json // package.json { "dependencies": { "@tauri-apps/plugin-notification": "^2.0.0" } } ``` ```javascript import { sendNotification } from '@tauri-apps/plugin-notification'; sendNotification('Tauri is awesome!'); ``` ```rust use tauri_plugin_notification::NotificationExt; use tauri::plugin::PermissionState; fn main() { tauri::Builder::default() .plugin(tauri_plugin_notification::init()) .setup(|app| { if app.notification().permission_state()? == PermissionState::Unknown { app.notification().request_permission()?; } if app.notification().permission_state()? == PermissionState::Granted { app.notification() .builder() .body("Tauri is awesome!") .show()?; } Ok(()) }) } ``` ### Migrate to Menu Module The Rust `Menu` APIs were moved to the `tauri::menu` module and refactored to use the [muda crate](https://github.com/tauri-apps/muda). #### Use `tauri::menu::MenuBuilder` Use `tauri::menu::MenuBuilder` instead of `tauri::Menu`. Note that its constructor takes a Manager instance (one of `App`, `AppHandle` or `WebviewWindow`) as an argument: ```rust use tauri::menu::MenuBuilder; tauri::Builder::default() .setup(|app| { let menu = MenuBuilder::new(app) .copy() .paste() .separator() .undo() .redo() .text("open-url", "Open URL") .check("toggle", "Toggle") .icon("show-app", "Show App", app.default_window_icon().cloned().unwrap()) .build()?; Ok(()) }) ``` #### Use `tauri::menu::PredefinedMenuItem` Use `tauri::menu::PredefinedMenuItem` instead of `tauri::MenuItem`: ```rust use tauri::menu::{MenuBuilder, PredefinedMenuItem}; tauri::Builder::default() .setup(|app| { let menu = MenuBuilder::new(app).item(&PredefinedMenuItem::copy(app)?).build()?; Ok(()) }) ``` :::tip The menu builder has dedicated methods to add each predefined menu item so you can call `.copy()` instead of `.item(&PredefinedMenuItem::copy(app, None)?)`. ::: #### Use `tauri::menu::MenuItemBuilder` Use `tauri::menu::MenuItemBuilder` instead of `tauri::CustomMenuItem`: ```rust use tauri::menu::MenuItemBuilder; tauri::Builder::default() .setup(|app| { let toggle = MenuItemBuilder::new("Toggle").accelerator("Ctrl+Shift+T").build(app)?; Ok(()) }) ``` #### Use `tauri::menu::SubmenuBuilder` Use `tauri::menu::SubmenuBuilder` instead of `tauri::Submenu`: ```rust use tauri::menu::{MenuBuilder, SubmenuBuilder}; tauri::Builder::default() .setup(|app| { let submenu = SubmenuBuilder::new(app, "Sub") .text("Tauri") .separator() .check("Is Awesome") .build()?; let menu = MenuBuilder::new(app).item(&submenu).build()?; Ok(()) }) ``` `tauri::Builder::menu` now takes a closure because the menu needs a Manager instance to be built. See [the documentation](https://docs.rs/tauri/2.0.0/tauri/struct.Builder.html#method.menu) for more information. #### Menu Events The Rust `tauri::Builder::on_menu_event` API was removed. Use `tauri::App::on_menu_event` or `tauri::AppHandle::on_menu_event` instead: ```rust use tauri::menu::{CheckMenuItemBuilder, MenuBuilder, MenuItemBuilder}; tauri::Builder::default() .setup(|app| { let toggle = MenuItemBuilder::with_id("toggle", "Toggle").build(app)?; let check = CheckMenuItemBuilder::new("Mark").build(app)?; let menu = MenuBuilder::new(app).items(&[&toggle, &check]).build()?; app.set_menu(menu)?; app.on_menu_event(move |app, event| { if event.id() == check.id() { println!("`check` triggered, do something! is checked? {}", check.is_checked().unwrap()); } else if event.id() == "toggle" { println!("toggle triggered!"); } }); Ok(()) }) ``` Note that there are two ways to check which menu item was selected: move the item to the event handler closure and compare IDs, or define a custom ID for the item through the `with_id` constructor and use that ID string to compare. :::tip Menu items can be shared across menus, and the menu event is bound to a menu item instead of a menu or window. If you don't want all listeners to be triggered when a menu item is selected, do not share menu items and use dedicated instances instead, that you could move into `tauri::WebviewWindow/WebviewWindowBuilder::on_menu_event` closure. ::: ### Migrate to OS Plugin The Rust `tauri::api::os` JavaScript `@tauri-apps/api/os` APIs have been removed. Use the `@tauri-apps/plugin-os` plugin instead: 1. Add to cargo dependencies: ```toml # Cargo.toml [dependencies] tauri-plugin-os = "2" ``` 2. Use in JavaScript or Rust project: ```rust fn main() { tauri::Builder::default() .plugin(tauri_plugin_os::init()) } ``` ```json // package.json { "dependencies": { "@tauri-apps/plugin-os": "^2.0.0" } } ``` ```javascript import { arch } from '@tauri-apps/plugin-os'; const architecture = await arch(); ``` ```rust fn main() { tauri::Builder::default() .plugin(tauri_plugin_os::init()) .setup(|app| { let os_arch = tauri_plugin_os::arch(); Ok(()) }) } ``` ### Migrate to Process Plugin The Rust `tauri::api::process` JavaScript `@tauri-apps/api/process` APIs have been removed. Use the `@tauri-apps/plugin-process` plugin instead: 1. Add to cargo dependencies: ```toml # Cargo.toml [dependencies] tauri-plugin-process = "2" ``` 2. Use in JavaScript or Rust project: ```rust fn main() { tauri::Builder::default() .plugin(tauri_plugin_process::init()) } ``` ```json // package.json { "dependencies": { "@tauri-apps/plugin-process": "^2.0.0" } } ``` ```javascript import { exit, relaunch } from '@tauri-apps/plugin-process'; await exit(0); await relaunch(); ``` ```rust fn main() { tauri::Builder::default() .plugin(tauri_plugin_process::init()) .setup(|app| { // exit the app with a status code app.handle().exit(1); // restart the app app.handle().restart(); Ok(()) }) } ``` ### Migrate to Shell Plugin The Rust `tauri::api::shell` JavaScript `@tauri-apps/api/shell` APIs have been removed. Use the `@tauri-apps/plugin-shell` plugin instead: 1. Add to cargo dependencies: ```toml # Cargo.toml [dependencies] tauri-plugin-shell = "2" ``` 2. Use in JavaScript or Rust project: ```rust fn main() { tauri::Builder::default() .plugin(tauri_plugin_shell::init()) } ``` ```json // package.json { "dependencies": { "@tauri-apps/plugin-shell": "^2.0.0" } } ``` ```javascript import { Command, open } from '@tauri-apps/plugin-shell'; const output = await Command.create('echo', 'message').execute(); await open('https://github.com/tauri-apps/tauri'); ``` - Open an URL ```rust use tauri_plugin_shell::ShellExt; fn main() { tauri::Builder::default() .plugin(tauri_plugin_shell::init()) .setup(|app| { app.shell().open("https://github.com/tauri-apps/tauri", None)?; Ok(()) }) } ``` - Spawn a child process and retrieve the status code ```rust use tauri_plugin_shell::ShellExt; fn main() { tauri::Builder::default() .plugin(tauri_plugin_shell::init()) .setup(|app| { let status = tauri::async_runtime::block_on(async move { app.shell().command("which").args(["ls"]).status().await.unwrap() }); println!("`which` finished with status: {:?}", status.code()); Ok(()) }) } ``` - Spawn a child process and capture its output ```rust use tauri_plugin_shell::ShellExt; fn main() { tauri::Builder::default() .plugin(tauri_plugin_shell::init()) .setup(|app| { let output = tauri::async_runtime::block_on(async move { app.shell().command("echo").args(["TAURI"]).output().await.unwrap() }); assert!(output.status.success()); assert_eq!(String::from_utf8(output.stdout).unwrap(), "TAURI"); Ok(()) }) } ``` - Spawn a child process and read its events asynchronously: ```rust use tauri_plugin_shell::{ShellExt, process::CommandEvent}; fn main() { tauri::Builder::default() .plugin(tauri_plugin_shell::init()) .setup(|app| { let handle = app.handle().clone(); tauri::async_runtime::spawn(async move { let (mut rx, mut child) = handle.shell().command("cargo") .args(["tauri", "dev"]) .spawn() .expect("Failed to spawn cargo"); let mut i = 0; while let Some(event) = rx.recv().await { if let CommandEvent::Stdout(line) = event { println!("got: {}", String::from_utf8(line).unwrap()); i += 1; if i == 4 { child.write("message from Rust\n".as_bytes()).unwrap(); i = 0; } } } }); Ok(()) }) } ``` ### Migrate to Tray Icon Module The Rust `SystemTray` APIs were renamed to `TrayIcon` for consistency. The new APIs can be found in the Rust `tray` module. #### Use `tauri::tray::TrayIconBuilder` Use `tauri::tray::TrayIconBuilder` instead of `tauri::SystemTray`: ```rust let tray = tauri::tray::TrayIconBuilder::with_id("my-tray").build(app)?; ``` See [TrayIconBuilder](https://docs.rs/tauri/2.0.0/tauri/tray/struct.TrayIconBuilder.html) for more information. #### Migrate to Menu Use `tauri::menu::Menu` instead of `tauri::SystemTrayMenu`, `tauri::menu::Submenu` instead of `tauri::SystemTraySubmenu` and `tauri::menu::PredefinedMenuItem` instead of `tauri::SystemTrayMenuItem`. #### Tray Events `tauri::SystemTray::on_event` have been split into `tauri::tray::TrayIconBuilder::on_menu_event` and `tauri::tray::TrayIconBuilder::on_tray_icon_event`: ```rust use tauri::{ menu::{MenuBuilder, MenuItemBuilder}, tray::{MouseButton, MouseButtonState, TrayIconBuilder, TrayIconEvent}, }; tauri::Builder::default() .setup(|app| { let toggle = MenuItemBuilder::with_id("toggle", "Toggle").build(app)?; let menu = MenuBuilder::new(app).items(&[&toggle]).build()?; let tray = TrayIconBuilder::new() .menu(&menu) .on_menu_event(move |app, event| match event.id().as_ref() { "toggle" => { println!("toggle clicked"); } _ => (), }) .on_tray_icon_event(|tray, event| { if let TrayIconEvent::Click { button: MouseButton::Left, button_state: MouseButtonState::Up, .. } = event { let app = tray.app_handle(); if let Some(webview_window) = app.get_webview_window("main") { let _ = webview_window.show(); let _ = webview_window.set_focus(); } } }) .build(app)?; Ok(()) }) ``` ### Migrate to Updater Plugin :::caution[Change of default behavior] The built-in dialog with an automatic update check was removed, use the Rust and JS APIs to check for and install updates instead. Failing to do so will prevent your users from getting further updates! ::: The Rust `tauri::updater` and JavaScript `@tauri-apps/api-updater` APIs have been removed. To set a custom updater target with the `@tauri-apps/plugin-updater`: 1. Add to cargo dependencies: ```toml [dependencies] tauri-plugin-updater = "2" ``` 2. Use in JavaScript or Rust project: ```rust fn main() { tauri::Builder::default() .plugin(tauri_plugin_updater::Builder::new().build()) } ``` ```json // package.json { "dependencies": { "@tauri-apps/plugin-updater": "^2.0.0" } } ``` ```javascript import { check } from '@tauri-apps/plugin-updater'; import { relaunch } from '@tauri-apps/plugin-process'; const update = await check(); if (update?.available) { console.log(`Update to ${update.version} available! Date: ${update.date}`); console.log(`Release notes: ${update.body}`); await update.downloadAndInstall(); // requires the `process` plugin await relaunch(); } ``` To check for updates: ```rust use tauri_plugin_updater::UpdaterExt; fn main() { tauri::Builder::default() .plugin(tauri_plugin_updater::Builder::new().build()) .setup(|app| { let handle = app.handle(); tauri::async_runtime::spawn(async move { let response = handle.updater().check().await; }); Ok(()) }) } ``` To set a custom updater target: ```rust fn main() { let mut updater = tauri_plugin_updater::Builder::new(); #[cfg(target_os = "macos")] { updater = updater.target("darwin-universal"); } tauri::Builder::default() .plugin(updater.build()) } ``` ### Migrate Path to Tauri Manager The Rust `tauri::api::path` module functions and `tauri::PathResolver` have been moved to `tauri::Manager::path`: ```rust use tauri::{path::BaseDirectory, Manager}; tauri::Builder::default() .setup(|app| { let home_dir_path = app.path().home_dir().expect("failed to get home dir"); let path = app.path().resolve("path/to/something", BaseDirectory::Config)?; Ok(()) }) ``` ### Migrate to new Window API On the Rust side, `Window` was renamed to `WebviewWindow`, its builder `WindowBuilder` is now named `WebviewWindowBuilder` and `WindowUrl` is now named `WebviewUrl`. Additionally, the `Manager::get_window` function was renamed to `get_webview_window` and the window's `parent_window` API was renamed to `parent_raw` to support a high level window parent API. On the JavaScript side, the `WebviewWindow` class is now exported in the `@tauri-apps/api/webviewWindow` path. The `onMenuClicked` function was removed, you can intercept menu events when creating a menu in JavaScript instead. ### Migrate Embedded Additional Files (Resources) On the JavaScript side, make sure you [Migrate to File System Plugin](#migrate-to-file-system-plugin). Additionally, note the changes made to the v1 allowlist in [Migrate Permissions](#migrate-permissions). On the Rust side, make sure you [Migrate Path to Tauri Manager](#migrate-path-to-tauri-manager). ### Migrate Embedded External Binaries (Sidecar) In Tauri v1, the external binaries and their arguments were defined in the allowlist. In v2, use the new permissions system. Read [Migrate Permissions](#migrate-permissions) for more information. On the JavaScript side, make sure you [Migrate to Shell Plugin](#migrate-to-shell-plugin). On the Rust side, `tauri::api::process` API has been removed. Use `tauri_plugin_shell::ShellExt` and `tauri_plugin_shell::process::CommandEvent` APIs instead. Read the [Embedding External Binaries](/develop/sidecar/#running-it-from-rust) guide to see how. The "process-command-api" features flag has been removed in v2. So running the external binaries does not require this feature to be defined in the Tauri config anymore. ### Migrate Permissions The v1 allowlist have been rewritten to a completely new system for permissions that works for individual plugins and is much more configurable for multiwindow and remote URL support. This new system works like an access control list (ACL) where you can allow or deny commands, allocate permissions to a specific set of windows and domains, and define access scopes. To enable permissions for your app, you must create capability files inside the `src-tauri/capabilities` folder, and Tauri will automatically configure everything else for you. The `migrate` CLI command automatically parses your v1 allowlist and generates the associated capability file. To learn more about permissions and capabilities, see [the security documentation](/security/). # Upgrade from Tauri 2.0 Beta import { Tabs, TabItem } from '@astrojs/starlight/components'; import CommandTabs from '@components/CommandTabs.astro'; This guide walks you through upgrading your Tauri 2.0 beta application to Tauri 2.0 release candidate. ## Automated Migration The Tauri v2 CLI includes a `migrate` command that automates most of the process and helps you finish the migration: Learn more about the `migrate` command in the [Command Line Interface reference](/reference/cli/#migrate) ## Breaking Changes We have had several breaking changes going from beta to release candidate. These can be either auto-migrated (see above) or manually performed. ### Tauri Core Plugins We changed how Tauri built-in plugins are addressed in the capabilities [PR #10390](https://github.com/tauri-apps/tauri/pull/10390). To migrate from the latest beta version you need to prepend all core permission identifiers in your capabilities with `core:` or switch to the `core:default` permission and remove old core plugin identifiers. ```json ... "permissions": [ "path:default", "event:default", "window:default", "app:default", "image:default", "resources:default", "menu:default", "tray:default", ] ... ``` ```json ... "permissions": [ "core:path:default", "core:event:default", "core:window:default", "core:app:default", "core:image:default", "core:resources:default", "core:menu:default", "core:tray:default", ] ... ``` We also added a new special `core:default` permission set which will contain all default permissions of all core plugins, so you can simplify the permissions boilerplate in your capabilities config. ```json ... "permissions": [ "core:default" ] ... ``` ### Built-In Development Server We introduced changes to the network exposure of the built-in development server [PR #10437](https://github.com/tauri-apps/tauri/pull/10437) and [PR #10456](https://github.com/tauri-apps/tauri/pull/10456). The built-in mobile development server no longer exposes network wide and tunnels traffic from the local machine directly to the device. Currently this improvement does not automatically apply when running on iOS devices (either directly or from Xcode). In this case we default to using the public network address for the development server, but there's a way around it which involves opening Xcode to automatically start a connection between your macOS machine and your connected iOS device, then running `tauri ios dev --force-ip-prompt` to select the iOS device's TUN address (ends with **::2**). Your development server configuration needs to adapt to this change if running on a physical iOS device is intended. Previously we recommended checking if the `TAURI_ENV_PLATFORM` environment variable matches either `android` or `ios`, but since we can now connect to localhost unless using an iOS device, you should instead check the `TAURI_DEV_HOST` environment variable. Here's an example of a Vite configuration migration: - 2.0.0-beta: ```js import { defineConfig } from 'vite'; import { svelte } from '@sveltejs/vite-plugin-svelte'; import { internalIpV4Sync } from 'internal-ip'; const mobile = !!/android|ios/.exec(process.env.TAURI_ENV_PLATFORM); export default defineConfig({ plugins: [svelte()], clearScreen: false, server: { host: mobile ? '0.0.0.0' : false, port: 1420, strictPort: true, hmr: mobile ? { protocol: 'ws', host: internalIpV4Sync(), port: 1421, } : undefined, }, }); ``` - 2.0.0: ```js import { defineConfig } from 'vite'; import Unocss from 'unocss/vite'; import { svelte } from '@sveltejs/vite-plugin-svelte'; const host = process.env.TAURI_DEV_HOST; export default defineConfig({ plugins: [svelte()], clearScreen: false, server: { host: host || false, port: 1420, strictPort: true, hmr: host ? { protocol: 'ws', host: host, port: 1430, } : undefined, }, }); ``` :::note The `internal-ip` NPM package is no longer required, you can directly use the TAURI_DEV_HOST value instead. ::: # Prerequisites import { Tabs, TabItem, Card } from '@astrojs/starlight/components'; In order to get started building your project with Tauri you'll first need to install a few dependencies: 1. [System Dependencies](#system-dependencies) 2. [Rust](#rust) 3. [Configure for Mobile Targets](#configure-for-mobile-targets) (only required if developing for mobile) ## System Dependencies Follow the link to get started for your respective operating system: - [Linux](#linux) (see below for specific distributions) - [macOS Catalina (10.15) and later](#macos) - [Windows 7 and later](#windows) ### Linux Tauri requires various system dependencies for development on Linux. These may be different depending on your distribution but we've included some popular distributions below to help you get setup. ```sh sudo apt update sudo apt install libwebkit2gtk-4.1-dev \ build-essential \ curl \ wget \ file \ libxdo-dev \ libssl-dev \ libayatana-appindicator3-dev \ librsvg2-dev ``` ```sh sudo pacman -Syu sudo pacman -S --needed \ webkit2gtk-4.1 \ base-devel \ curl \ wget \ file \ openssl \ appmenu-gtk-module \ libappindicator-gtk3 \ librsvg ``` ```sh sudo dnf check-update sudo dnf install webkit2gtk4.1-devel \ openssl-devel \ curl \ wget \ file \ libappindicator-gtk3-devel \ librsvg2-devel sudo dnf group install "c-development" ``` ```sh sudo emerge --ask \ net-libs/webkit-gtk:4.1 \ dev-libs/libappindicator \ net-misc/curl \ net-misc/wget \ sys-apps/file ``` ```sh sudo zypper up sudo zypper in webkit2gtk3-devel \ libopenssl-devel \ curl \ wget \ file \ libappindicator3-1 \ librsvg-devel sudo zypper in -t pattern devel_basis ``` ```sh sudo apk add \ build-base \ webkit2gtk \ curl \ wget \ file \ openssl \ libayatana-appindicator-dev \ librsvg ``` :::note This will also install Rust and Node.js as well as the `cargo-tauri` CLI for you, so you can skip those steps below. ::: Using `nix-shell`: ```nix let pkgs = import { }; in pkgs.mkShell { nativeBuildInputs = with pkgs; [ pkg-config gobject-introspection cargo cargo-tauri nodejs ]; buildInputs = with pkgs;[ at-spi2-atk atkmm cairo gdk-pixbuf glib gtk3 harfbuzz librsvg libsoup_3 pango webkitgtk_4_1 openssl ]; } ``` If your distribution isn't included above then you may want to check [Awesome Tauri on GitHub](https://github.com/tauri-apps/awesome-tauri#guides) to see if a guide has been created. Next: [Install Rust](#rust) ### macOS Tauri uses [Xcode](https://developer.apple.com/xcode/resources/) and various macOS and iOS development dependencies. Download and install Xcode from one of the following places: - [Mac App Store](https://apps.apple.com/gb/app/xcode/id497799835?mt=12) - [Apple Developer website](https://developer.apple.com/xcode/resources/). Be sure to launch Xcode after installing so that it can finish setting up.
Only developing for desktop targets? If you're only planning to develop desktop apps and not targeting iOS then you can install Xcode Command Line Tools instead: ```sh xcode-select --install ```
Next: [Install Rust](#rust) ### Windows Tauri uses the Microsoft C++ Build Tools for development as well as Microsoft Edge WebView2. These are both required for development on Windows. Follow the steps below to install the required dependencies. #### Microsoft C++ Build Tools 1. Download the [Microsoft C++ Build Tools](https://visualstudio.microsoft.com/visual-cpp-build-tools/) installer and open it to begin installation. 2. During installation check the "Desktop development with C++" option. ![Visual Studio C++ Build Tools installer screenshot](@assets/start/prerequisites/visual-studio-build-tools-installer.png) Next: [Install WebView2](#webview2). #### WebView2 :::tip WebView 2 is already installed on Windows 10 (from version 1803 onward) and later versions of Windows. If you are developing on one of these versions then you can skip this step and go directly to [installing Rust](#rust). ::: Tauri uses Microsoft Edge WebView2 to render content on Windows. Install WebView2 by visiting the [WebView2 Runtime download section](https://developer.microsoft.com/en-us/microsoft-edge/webview2/#download-section). Download the "Evergreen Bootstrapper" and install it. Next: [Install Rust](#rust) ## Rust Tauri is built with [Rust](https://www.rust-lang.org) and requires it for development. Install Rust using one of following methods. You can view more installation methods at https://www.rust-lang.org/tools/install. Install via [`rustup`](https://github.com/rust-lang/rustup) using the following command: ```sh curl --proto '=https' --tlsv1.2 https://sh.rustup.rs -sSf | sh ``` :::tip[Security Tip] We have audited this bash script, and it does what it says it is supposed to do. Nevertheless, before blindly curl-bashing a script, it is always wise to look at it first. Here is the file as a plain script: [rustup.sh](https://sh.rustup.rs/) ::: Visit https://www.rust-lang.org/tools/install to install `rustup`. Alternatively, you can use `winget` to install rustup using the following command in PowerShell: ```powershell winget install --id Rustlang.Rustup ``` :::caution[MSVC toolchain as default] For full support for Tauri and tools like [`trunk`](https://trunkrs.dev/) make sure the MSVC Rust toolchain is the selected `default host triple` in the installer dialog. Depending on your system it should be either `x86_64-pc-windows-msvc`, `i686-pc-windows-msvc`, or `aarch64-pc-windows-msvc`. If you already have Rust installed, you can make sure the correct toolchain is installed by running this command: ```powershell rustup default stable-msvc ``` ::: **Be sure to restart your Terminal (and in some cases your system) for the changes to take affect.** Next: [Configure for Mobile Targets](#configure-for-mobile-targets) if you'd like to build for Android and iOS, or, if you'd like to use a JavaScript framework, [install Node](#nodejs). Otherwise [Create a Project](/start/create-project/). ## Node.js :::note[JavaScript ecosystem] Only if you intend to use a JavaScript frontend framework ::: 1. Go to the [Node.js website](https://nodejs.org), download the Long Term Support (LTS) version and install it. 2. Check if Node was successfully installed by running: ```sh node -v # v20.10.0 npm -v # 10.2.3 ``` It's important to restart your Terminal to ensure it recognizes the new installation. In some cases, you might need to restart your computer. While npm is the default package manager for Node.js, you can also use others like pnpm or yarn. To enable these, run `corepack enable` in your Terminal. This step is optional and only needed if you prefer using a package manager other than npm. Next: [Configure for Mobile Targets](#configure-for-mobile-targets) or [Create a project](/start/create-project/). ## Configure for Mobile Targets If you'd like to target your app for Android or iOS then there are a few additional dependencies that you need to install: - [Android](#android) - [iOS](#ios) ### Android 1. Download and install [Android Studio from the Android Developers website](https://developer.android.com/studio) 2. Set the `JAVA_HOME` environment variable: {/* TODO: Can this be done in the 4th step? */} ```sh export JAVA_HOME=/opt/android-studio/jbr ``` ```sh export JAVA_HOME="/Applications/Android Studio.app/Contents/jbr/Contents/Home" ``` ```ps [System.Environment]::SetEnvironmentVariable("JAVA_HOME", "C:\Program Files\Android\Android Studio\jbr", "User") ``` 3. Use the SDK Manager in Android Studio to install the following: - Android SDK Platform - Android SDK Platform-Tools - NDK (Side by side) - Android SDK Build-Tools - Android SDK Command-line Tools Selecting "Show Package Details" in the SDK Manager enables the installation of older package versions. Only install older versions if necessary, as they may introduce compatibility issues or security risks. 4. Set `ANDROID_HOME` and `NDK_HOME` environment variables. ```sh export ANDROID_HOME="$HOME/Android/Sdk" export NDK_HOME="$ANDROID_HOME/ndk/$(ls -1 $ANDROID_HOME/ndk)" ``` ```sh export ANDROID_HOME="$HOME/Library/Android/sdk" export NDK_HOME="$ANDROID_HOME/ndk/$(ls -1 $ANDROID_HOME/ndk)" ``` ```ps [System.Environment]::SetEnvironmentVariable("ANDROID_HOME", "$env:LocalAppData\Android\Sdk", "User") $VERSION = Get-ChildItem -Name "$env:LocalAppData\Android\Sdk\ndk" [System.Environment]::SetEnvironmentVariable("NDK_HOME", "$env:LocalAppData\Android\Sdk\ndk\$VERSION", "User") ``` :::tip PowerShell will not pick up the new environment variables until reboot or logout, However you can refresh the current session: ````ps [System.Environment]::GetEnvironmentVariables("User").GetEnumerator() | % { Set-Item -Path "Env:\$($_.key)" -Value $_.value } ::: 5. Add the Android targets with `rustup`: ```sh rustup target add aarch64-linux-android armv7-linux-androideabi i686-linux-android x86_64-linux-android ```` Next: [Setup for iOS](#ios) or [Create a project](/start/create-project/). ### iOS :::caution[macOS Only] iOS development requires Xcode and is only available on macOS. Be sure that you've installed Xcode and not Xcode Command Line Tools in the [macOS system dependencies section](#macos). ::: 1. Add the iOS targets with `rustup` in Terminal: ```sh rustup target add aarch64-apple-ios x86_64-apple-ios aarch64-apple-ios-sim ``` 2. Install [Homebrew](https://brew.sh): ```sh /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" ``` 3. Install [Cocoapods](https://cocoapods.org) using Homebrew: ```sh brew install cocoapods ``` Next: [Create a project](/start/create-project/). ## Troubleshooting If you run into any issues during installation be sure to check the [Troubleshooting Guide](/develop/debug/) or reach out on the [Tauri Discord](https://discord.com/invite/tauri). Now that you've installed all of the prerequisites you're ready to [create your first Tauri project](/start/create-project/)! # Concept # Core Concepts import { CardGrid, LinkCard } from '@astrojs/starlight/components'; Tauri has a variety of topics that are considered to be core concepts, things any developer should be aware of when developing their applications. Here's a variety of topics that you should get more intimately familiar with if you want to get the most out of the framework. # Tauri Architecture ## Introduction Tauri is a polyglot and generic toolkit that is very composable and allows engineers to make a wide variety of applications. It is used for building applications for desktop computers using a combination of Rust tools and HTML rendered in a Webview. Apps built with Tauri can ship with any number of pieces of an optional JS API and Rust API so that webviews can control the system via message passing. Developers can extend the default API with their own functionality and bridge the Webview and Rust-based backend easily. Tauri apps can have [tray-type interfaces](/learn/system-tray/). They can be [updated](/plugin/updater/) and are managed by the user's operating system as expected. They are very small because they use the OS's webview. They do not ship a runtime since the final binary is compiled from Rust. This makes the [reversing of Tauri apps not a trivial task](/security/). ### What Tauri is Not Tauri is not a lightweight kernel wrapper. Instead, it directly uses [WRY](#wry) and [TAO](#tao) to do the heavy lifting in making system calls to the OS. Tauri is not a VM or virtualized environment. Instead, it is an application toolkit that allows making Webview OS applications. ## Core Ecosystem
```d2 sketch pad=50 direction: up Core: { shape: rectangle "tauri": { "tauri-runtime" "tauri-macros" "tauri-utils" } "tauri-build" "tauri-codegen" "tauri-runtime-wry" } Upstream: { shape: rectangle direction: right WRY TAO } Core."tauri"."tauri-runtime" -> Core."tauri-runtime-wry"{style.animated: true} Upstream.WRY -> Upstream.TAO{style.animated: true} Core."tauri-runtime-wry" -> Upstream.Wry {style.animated: true} ```
Simplified representation of the Tauri architecture.
### tauri [View on GitHub](https://github.com/tauri-apps/tauri/tree/dev/crates/tauri) This is the major crate that holds everything together. It brings the runtimes, macros, utilities and API into one final product. It reads the [`tauri.conf.json`](/reference/config/) file at compile time to bring in features and undertake the actual configuration of the app (and even the `Cargo.toml` file in the project's folder). It handles script injection (for polyfills / prototype revision) at runtime, hosts the API for systems interaction, and even manages the updating process. ### tauri-runtime [View on GitHub](https://github.com/tauri-apps/tauri/tree/dev/crates/tauri-runtime) The glue layer between Tauri itself and lower-level webview libraries. ### tauri-macros [View on GitHub](https://github.com/tauri-apps/tauri/tree/dev/crates/tauri-macros) Creates macros for the context, handler, and commands by leveraging the [`tauri-codegen`](https://github.com/tauri-apps/tauri/tree/dev/crates/tauri-codegen) crate. ### tauri-utils [View on GitHub](https://github.com/tauri-apps/tauri/tree/dev/crates/tauri-utils) Common code that is reused in many places and offers useful utilities like parsing configuration files, detecting platform triples, injecting the CSP, and managing assets. ### tauri-build [View on GitHub](https://github.com/tauri-apps/tauri/tree/dev/crates/tauri-build) Applies the macros at build-time to rig some special features needed by `cargo`. ### tauri-codegen [View on GitHub](https://github.com/tauri-apps/tauri/tree/dev/crates/tauri-codegen) Embeds, hashes, and compresses assets, including icons for the app as well as the system tray. Parses [`tauri.conf.json`](/reference/config/) at compile time and generates the Config struct. ### tauri-runtime-wry [View on GitHub](https://github.com/tauri-apps/tauri/tree/dev/crates/tauri-runtime-wry) This crate opens up direct systems-level interactions specifically for WRY, such as printing, monitor detection, and other windowing-related tasks. ## Tauri Tooling ### API (JavaScript / TypeScript) [View on GitHub](https://github.com/tauri-apps/tauri/tree/dev/packages/api) A typescript library that creates `cjs` and `esm` JavaScript endpoints for you to import into your frontend framework so that the Webview can call and listen to backend activity. Also ships in pure typescript, because for some frameworks this is more optimal. It uses the message passing of webviews to their hosts. ### Bundler (Rust / Shell) [View on GitHub](https://github.com/tauri-apps/tauri/tree/dev/crates/tauri-bundler) A library that builds a Tauri app for the platform it detects or is told. Currently supports macOS, Windows and Linux - but in the near future will support mobile platforms as well. May be used outside of Tauri projects. ### cli.rs (Rust) [View on GitHub](https://github.com/tauri-apps/tauri/tree/dev/crates/tauri-cli) This Rust executable provides the full interface to all of the required activities for which the CLI is required. It runs on macOS, Windows, and Linux. ### cli.js (JavaScript) [View on GitHub](https://github.com/tauri-apps/tauri/tree/dev/packages/cli) Wrapper around [`cli.rs`](https://github.com/tauri-apps/tauri/blob/dev/crates/tauri-cli) using [`napi-rs`](https://github.com/napi-rs/napi-rs) to produce npm packages for each platform. ### create-tauri-app (JavaScript) [View on GitHub](https://github.com/tauri-apps/create-tauri-app) A toolkit that will enable engineering teams to rapidly scaffold out a new `tauri-apps` project using the frontend framework of their choice (as long as it has been configured). ## Upstream Crates The Tauri-Apps organization maintains two "upstream" crates from Tauri, namely TAO for creating and managing application windows, and WRY for interfacing with the Webview that lives within the window. ### TAO [View on GitHub](https://github.com/tauri-apps/tao) Cross-platform application window creation library in Rust that supports all major platforms like Windows, macOS, Linux, iOS and Android. Written in Rust, it is a fork of [winit](https://github.com/rust-windowing/winit) that we have extended for our own needs - like menu bar and system tray. ### WRY [View on GitHub](https://github.com/tauri-apps/wry) WRY is a cross-platform WebView rendering library in Rust that supports all major desktop platforms like Windows, macOS, and Linux. Tauri uses WRY as the abstract layer responsible to determine which webview is used (and how interactions are made). ## Additional Tooling ### tauri-action [View on GitHub](https://github.com/tauri-apps/tauri-action) GitHub workflow that builds Tauri binaries for all platforms. Even allows creating a (very basic) Tauri app even if Tauri is not set up. ### tauri-vscode [View on GitHub](https://github.com/tauri-apps/tauri-vscode) This project enhances the Visual Studio Code interface with several nice-to-have features. ### vue-cli-plugin-tauri [View on GitHub](https://github.com/tauri-apps/vue-cli-plugin-tauri) Allows you to very quickly install Tauri in a vue-cli project. ## Plugins [Tauri Plugin Guide](/develop/plugins/) Generally speaking, plugins are authored by third parties (even though there may be official, supported plugins). A plugin generally does 3 things: 1. Enables Rust code to do "something". 2. Provides interface glue to make it easy to integrate into an app. 3. Provides a JavaScript API for interfacing with the Rust code. Here are some examples of Tauri Plugins: - [tauri-plugin-fs](https://github.com/tauri-apps/tauri-plugin-fs) - [tauri-plugin-sql](https://github.com/tauri-apps/tauri-plugin-sql) - [tauri-plugin-stronghold](https://github.com/tauri-apps/tauri-plugin-stronghold) ## License Tauri itself is licensed under MIT or Apache-2.0. If you repackage it and modify any source code, it is your responsibility to verify that you are complying with all upstream licenses. Tauri is provided AS-IS with no explicit claim for suitability for any purpose. Here you may peruse our [Software Bill of Materials](https://app.fossa.com/projects/git%2Bgithub.com%2Ftauri-apps%2Ftauri). # Inter-Process Communication import { CardGrid, LinkCard } from '@astrojs/starlight/components'; Inter-Process Communication (IPC) allows isolated processes to communicate securely and is key to building more complex applications. Learn more about the specific IPC patterns in the following guides: Tauri uses a particular style of Inter-Process Communication called [Asynchronous Message Passing], where processes exchange _requests_ and _responses_ serialized using some simple data representation. Message Passing should sound familiar to anyone with web development experience, as this paradigm is used for client-server communication on the internet. Message passing is a safer technique than shared memory or direct function access because the recipient is free to reject or discard requests as it sees fit. For example, if the Tauri Core process determines a request to be malicious, it simply discards the requests and never executes the corresponding function. In the following, we explain Tauri's two IPC primitives - `Events` and `Commands` - in more detail. ## Events Events are fire-and-forget, one-way IPC messages that are best suited to communicate lifecycle events and state changes. Unlike [Commands](#commands), Events can be emitted by both the Frontend _and_ the Tauri Core.
```d2 sketch pad=50 shape: sequence_diagram Frontend: { shape: rectangle label: "Webview\nFrontend" } Core: { shape: rectangle label: "Core\nBackend" } Frontend -> Core: "Event"{style.animated: true} Core -> Frontend: "Event"{style.animated: true} ```
Events sent between the Core and the Webview.
## Commands Tauri also provides a [foreign function interface]-like abstraction on top of IPC messages[^1]. The primary API, `invoke`, is similar to the browser's `fetch` API and allows the Frontend to invoke Rust functions, pass arguments, and receive data. Because this mechanism uses a [JSON-RPC] like protocol under the hood to serialize requests and responses, all arguments and return data must be serializable to JSON.
```d2 sketch pad=50 shape: sequence_diagram Frontend: { label: "Webview\nFrontend" } Core: { label: "Core\nBackend" } InvokeHandler: { label: "Invoke\nHandler" } Frontend -> Core: "IPC Request"{style.animated: true} Core -> InvokeHandler: "Invoke command"{style.animated: true} InvokeHandler -> Core: "Serialize return"{style.animated: true} Core -> Frontend: "Response"{style.animated: true} ```
IPC messages involved in a command invocation.
[^1]: Because Commands still use message passing under the hood, they do not share the same security pitfalls as real FFI interfaces do. [asynchronous message passing]: https://en.wikipedia.org/wiki/Message_passing#Asynchronous_message_passing [json-rpc]: https://www.jsonrpc.org [foreign function interface]: https://en.wikipedia.org/wiki/Foreign_function_interface # Brownfield Pattern _**This is the default pattern.**_ This is the simplest and most straightforward pattern to use Tauri with, because it tries to be as compatible as possible with existing frontend projects. In short, it tries to require nothing additional to what an existing web frontend might use inside a browser. Not _**everything**_ that works in existing browser applications will work out-of-the-box. If you are unfamiliar with Brownfield software development in general, the [Brownfield Wikipedia article] provides a nice summary. For Tauri, the existing software is current browser support and behavior, instead of legacy systems. ## Configuration Because the Brownfield pattern is the default pattern, it doesn't require a configuration option to be set. To explicitly set it, you can use the `tauri > pattern` object in the `tauri.conf.json` configuration file. ```json { "tauri": { "pattern": { "use": "brownfield" } } } ``` _**There are no additional configuration options for the brownfield pattern.**_ [brownfield wikipedia article]: https://en.wikipedia.org/wiki/Brownfield_(software_development) # Isolation Pattern The Isolation pattern is a way to intercept and modify Tauri API messages sent by the frontend before they get to Tauri Core, all with JavaScript. The secure JavaScript code that is injected by the Isolation pattern is referred to as the Isolation application. ## Why The Isolation pattern's purpose is to provide a mechanism for developers to help protect their application from unwanted or malicious frontend calls to Tauri Core. The need for the Isolation pattern rose out of threats coming from untrusted content running on the frontend, a common case for applications with many dependencies. See [Security: Threat Models] for a list of many sources of threats that an application may see. The largest threat model described above that the Isolation pattern was designed in mind was Development Threats. Not only do many frontend build-time tools consist of many dozen (or hundreds) of often deeply-nested dependencies, but a complex application may also have a large amount of (also often deeply-nested) dependencies that are bundled into the final output. ## When Tauri highly recommends using the isolation pattern whenever it can be used. Because the Isolation application intercepts _**all**_ messages from the frontend, it can _always_ be used. Tauri also strongly suggests locking down your application whenever you use external Tauri APIs. As the developer, you can utilize the secure Isolation application to try and verify IPC inputs, to make sure they are within some expected parameters. For example, you may want to check that a call to read or write a file is not trying to access a path outside your application's expected locations. Another example is making sure that a Tauri API HTTP fetch call is only setting the Origin header to what your application expects it to be. That said, it intercepts _**all**_ messages from the frontend, so it will even work with always-on APIs such as [Events]. Since some events may cause your own rust code to perform actions, the same sort of validation techniques can be used with them. ## How The Isolation pattern is all about injecting a secure application in between your frontend and Tauri Core to intercept and modify incoming IPC messages. It does this by using the sandboxing feature of `