Tauri Migration Guide
This skill covers migrating Tauri applications to v2 stable from either v1 or v2 beta.
Migration Paths
Source Version Target Complexity
Tauri v1.x v2 stable High - significant breaking changes
Tauri v2 beta v2 stable Low - minor breaking changes
Automated Migration
Both migration paths support automated migration via the Tauri CLI:
Install latest CLI first
npm install @tauri-apps/cli@latest
Run migration
npm run tauri migrate
or: yarn tauri migrate | pnpm tauri migrate | cargo tauri migrate
IMPORTANT: The migrate command automates most tasks but is NOT a complete substitute for manual review. Always verify changes after running.
V1 to V2 Migration
Configuration File Changes
BREAKING: Top-Level Structure Changes
Before (v1):
{ "package": { "productName": "my-app", "version": "1.0.0" }, "tauri": { "bundle": { ... }, "allowlist": { ... } } }
After (v2):
{ "productName": "my-app", "version": "1.0.0", "mainBinaryName": "my-app", "identifier": "com.example.myapp", "app": { ... }, "bundle": { ... } }
Key Renames
v1 Path v2 Path
package.productName
productName (top-level)
package.version
version (top-level)
tauri
app
tauri.bundle
bundle (top-level)
tauri.bundle.identifier
identifier (top-level)
tauri.systemTray
app.trayIcon
build.distDir
frontendDist
build.devPath
devUrl
BREAKING: New Required Field
Add mainBinaryName matching your productName
- this is no longer automatic:
{ "productName": "My App", "mainBinaryName": "My App" }
Bundle Configuration Reorganization
Platform-specific bundle configs moved under their platform key:
Before:
{ "tauri": { "bundle": { "dmg": { ... }, "deb": { ... } } } }
After:
{ "bundle": { "macOS": { "dmg": { ... } }, "linux": { "deb": { ... } } } }
Updater Configuration
If using the app updater, add to bundle config:
{ "bundle": { "createUpdaterArtifacts": "v1Compatible" } }
Use "v1Compatible" for existing distributions to maintain backward compatibility.
BREAKING: Allowlist Replaced with Capabilities
The v1 allowlist system is completely replaced with a capability-based ACL system.
Creating Capabilities
Create JSON files in src-tauri/capabilities/ :
src-tauri/capabilities/default.json:
{ "identifier": "default", "description": "Default capabilities for the main window", "windows": ["main"], "permissions": [ "core:default", "shell:allow-open", "dialog:allow-open", "fs:allow-read-text-file" ] }
The tauri migrate command auto-generates capabilities from your v1 allowlist.
Cargo.toml Changes
Removed Features
These features no longer exist in v2:
-
reqwest-client
-
reqwest-native-tls-vendored
-
process-command-api
-
shell-open-api
-
windows7-compat
-
updater
-
system-tray
New Features
- linux-protocol-body
- Custom protocol request body parsing support
BREAKING: API Module Removal
The entire api module is removed. Functionality moved to plugins:
v1 API v2 Replacement
tauri::api::dialog
tauri-plugin-dialog
tauri::api::http
tauri-plugin-http
tauri::api::process
tauri-plugin-process
tauri::api::path functions tauri::Manager::path
BREAKING: Rust API Changes
Removed APIs
v1 v2 Alternative
App::clipboard_manager
tauri-plugin-clipboard-manager
App::global_shortcut_manager
tauri-plugin-global-shortcut
App::get_cli_matches
tauri-plugin-cli
tauri::updater
tauri-plugin-updater
Renamed Types/Methods
v1 v2
Window
WebviewWindow
Manager::get_window
Manager::get_webview_window
Menu API Changes
Before:
use tauri::{Menu, CustomMenuItem}; let menu = Menu::new() .add_item(CustomMenuItem::new("quit", "Quit"));
After:
use tauri::menu::{MenuBuilder, MenuItemBuilder}; let menu = MenuBuilder::new(app) .item(&MenuItemBuilder::with_id("quit", "Quit").build(app)?) .build()?;
Tray API Changes
Before:
use tauri::SystemTray; SystemTray::new().with_menu(menu);
After:
use tauri::tray::TrayIconBuilder; TrayIconBuilder::new() .menu(&menu) .on_menu_event(|app, event| { ... }) .on_tray_icon_event(|tray, event| { ... }) .build(app)?;
BREAKING: JavaScript API Changes
Package Renames
v1 v2
@tauri-apps/api/tauri
@tauri-apps/api/core
@tauri-apps/api/window
@tauri-apps/api/webviewWindow
Core API Reduction
The core @tauri-apps/api package now only includes:
-
core
-
path
-
event
-
webviewWindow
All other APIs require plugin packages.
BREAKING: Plugin Migration
All formerly built-in APIs are now separate plugins:
v1 Import v2 Plugin Package
@tauri-apps/api/cli
@tauri-apps/plugin-cli
@tauri-apps/api/clipboard
@tauri-apps/plugin-clipboard-manager
@tauri-apps/api/dialog
@tauri-apps/plugin-dialog
@tauri-apps/api/fs
@tauri-apps/plugin-fs
@tauri-apps/api/global-shortcut
@tauri-apps/plugin-global-shortcut
@tauri-apps/api/http
@tauri-apps/plugin-http
@tauri-apps/api/notification
@tauri-apps/plugin-notification
@tauri-apps/api/os
@tauri-apps/plugin-os
@tauri-apps/api/process
@tauri-apps/plugin-process
@tauri-apps/api/shell
@tauri-apps/plugin-shell
@tauri-apps/api/updater
@tauri-apps/plugin-updater
Installing Plugins
JavaScript
npm install @tauri-apps/plugin-fs
Rust (add to Cargo.toml)
cargo add tauri-plugin-fs
Register plugins in your Rust code:
fn main() { tauri::Builder::default() .plugin(tauri_plugin_fs::init()) .run(tauri::generate_context!()) .expect("error running app"); }
BREAKING: File System Plugin Changes
Function renames in @tauri-apps/plugin-fs :
v1 v2
createDir
mkdir
readBinaryFile
readFile
writeBinaryFile
writeFile
removeDir
remove
removeFile
remove
renameFile
rename
Dir enum BaseDirectory
BREAKING: Event System Changes
v1 v2
emit()
Broadcasts to ALL listeners (behavior change)
N/A emit_to()
- target specific event targets
listen_global
listen_any
BREAKING: Windows Origin URL
Production Windows apps now serve from http://tauri.localhost instead of https:// .
Impact: IndexedDB and cookies will reset unless you preserve the old behavior:
{ "app": { "windows": [{ "useHttpsScheme": true }] } }
BREAKING: Environment Variables
v1 v2
TAURI_PRIVATE_KEY
TAURI_SIGNING_PRIVATE_KEY
TAURI_KEY_PASSWORD
TAURI_SIGNING_PRIVATE_KEY_PASSWORD
TAURI_DEV_SERVER_PORT
TAURI_CLI_PORT
Platform variables Now prefixed TAURI_ENV_
Mobile Support Setup
To target mobile alongside desktop:
- Update Cargo.toml:
[lib] name = "app_lib" crate-type = ["staticlib", "cdylib", "rlib"]
- Rename src/main.rs to src/lib.rs:
#[cfg_attr(mobile, tauri::mobile_entry_point)] pub fn run() { tauri::Builder::default() .run(tauri::generate_context!()) .expect("error running app"); }
- Create new src/main.rs:
fn main() { app_lib::run(); }
V2 Beta to V2 Stable Migration
BREAKING: Core Permission Prefix
All core permissions now require the "core:" prefix:
Before (beta):
{ "permissions": [ "path:default", "event:default", "window:default" ] }
After (stable):
{ "permissions": [ "core:path:default", "core:event:default", "core:window:default" ] }
Simplified alternative: Use "core:default" to include all default core permissions:
{ "permissions": ["core:default"] }
BREAKING: Mobile Dev Server Configuration
The mobile development server no longer exposes across networks. Traffic tunnels directly from local machine to devices.
Before (beta):
const mobile = !!/android|ios/.exec(process.env.TAURI_ENV_PLATFORM); export default { server: { host: mobile ? '0.0.0.0' : false } };
After (stable):
const host = process.env.TAURI_DEV_HOST; export default { server: { host: host || false } };
Remove dependency on the internal-ip NPM package if previously used.
iOS Device Development: Requires additional steps. Use:
tauri ios dev --force-ip-prompt
Select the device's TUN address when prompted.
Migration Checklist
V1 to V2
-
Run npm run tauri migrate
-
Verify config structure changes (package -> top-level)
-
Add mainBinaryName field
-
Update bundle config structure
-
Replace allowlist with capabilities
-
Install required plugins
-
Update Rust imports (Window -> WebviewWindow)
-
Update JS imports (@tauri-apps/api/tauri -> core)
-
Update FS function names if using fs plugin
-
Update environment variable names
-
Test event system behavior
-
Verify Windows origin URL handling (IndexedDB/cookies)
-
Update menu/tray code if used
-
Remove deprecated Cargo features
V2 Beta to V2 Stable
-
Run npm run tauri migrate
-
Add core: prefix to permission identifiers (or use core:default )
-
Update mobile dev server configuration
-
Remove internal-ip package dependency if present
-
Test iOS device development with --force-ip-prompt
Common Issues
Issue Solution
Permission denied errors Check src-tauri/capabilities/ files for required permissions
IndexedDB/localStorage lost (Windows) Set useHttpsScheme: true in window config
Plugin not found Add to Cargo.toml, register with .plugin() , install npm package
Mobile build fails Verify [lib] section in Cargo.toml and src/lib.rs with mobile entry point