Assists users with migrating Tauri applications from v1 to v2 stable, and from v2 beta to v2 stable, covering breaking changes, configuration updates, API migrations, and plugin system changes.
Scanned 2/12/2026
Install via CLI
openskills install dchuk/claude-code-tauri-skills---
name: migrating-tauri-apps
description: Assists users with migrating Tauri applications from v1 to v2 stable, and from v2 beta to v2 stable, covering breaking changes, configuration updates, API migrations, and plugin system changes.
---
# 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:
```bash
# 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):**
```json
{
"package": {
"productName": "my-app",
"version": "1.0.0"
},
"tauri": {
"bundle": { ... },
"allowlist": { ... }
}
}
```
**After (v2):**
```json
{
"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:
```json
{
"productName": "My App",
"mainBinaryName": "My App"
}
```
#### Bundle Configuration Reorganization
Platform-specific bundle configs moved under their platform key:
**Before:**
```json
{
"tauri": {
"bundle": {
"dmg": { ... },
"deb": { ... }
}
}
}
```
**After:**
```json
{
"bundle": {
"macOS": {
"dmg": { ... }
},
"linux": {
"deb": { ... }
}
}
}
```
#### Updater Configuration
If using the app updater, add to bundle config:
```json
{
"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:**
```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:**
```rust
use tauri::{Menu, CustomMenuItem};
let menu = Menu::new()
.add_item(CustomMenuItem::new("quit", "Quit"));
```
**After:**
```rust
use tauri::menu::{MenuBuilder, MenuItemBuilder};
let menu = MenuBuilder::new(app)
.item(&MenuItemBuilder::with_id("quit", "Quit").build(app)?)
.build()?;
```
#### Tray API Changes
**Before:**
```rust
use tauri::SystemTray;
SystemTray::new().with_menu(menu);
```
**After:**
```rust
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
```bash
# JavaScript
npm install @tauri-apps/plugin-fs
# Rust (add to Cargo.toml)
cargo add tauri-plugin-fs
```
Register plugins in your Rust code:
```rust
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:
```json
{
"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:
**1. Update Cargo.toml:**
```toml
[lib]
name = "app_lib"
crate-type = ["staticlib", "cdylib", "rlib"]
```
**2. Rename src/main.rs to src/lib.rs:**
```rust
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
tauri::Builder::default()
.run(tauri::generate_context!())
.expect("error running app");
}
```
**3. Create new src/main.rs:**
```rust
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):**
```json
{
"permissions": [
"path:default",
"event:default",
"window:default"
]
}
```
**After (stable):**
```json
{
"permissions": [
"core:path:default",
"core:event:default",
"core:window:default"
]
}
```
**Simplified alternative:** Use `"core:default"` to include all default core permissions:
```json
{
"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):**
```javascript
const mobile = !!/android|ios/.exec(process.env.TAURI_ENV_PLATFORM);
export default {
server: {
host: mobile ? '0.0.0.0' : false
}
};
```
**After (stable):**
```javascript
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:
```bash
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 |
No comments yet. Be the first to comment!