.claude/skills/tauri-2/tauri-impl/tauri-impl-migration/SKILL.md
Use when migrating from Tauri 1 to Tauri 2, updating legacy Tauri code, or comparing v1 vs v2 APIs. Prevents retaining v1 allowlist config, deprecated API calls, and outdated import paths that break at compile time. Covers config restructuring, allowlist to permissions conversion, Rust and JS API renames, event and menu system changes. Keywords: tauri migration, v1 to v2, allowlist, permissions conversion, API rename, import path, upgrade.
npx skillsauth add OpenAEC-Foundation/OpenAEC-Workspace-Composer tauri-impl-migrationInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
npx @tauri-apps/cli migrate
This auto-converts v1 allowlist entries to capability files, updates Cargo dependencies, and restructures configuration. ALWAYS run this first before manual migration.
| Tauri v1 | Tauri v2 |
|----------|----------|
| package.productName | productName (top-level) |
| package.version | version (top-level) |
| tauri | app |
| tauri.allowlist | Removed -- replaced by capabilities/permissions |
| tauri.bundle | bundle (top-level) |
| tauri.cli | plugins.cli |
| tauri.updater | plugins.updater |
| tauri.systemTray | app.trayIcon |
| tauri.allowlist.protocol.assetScope | app.security.assetProtocol.scope |
| tauri.pattern | app.security.pattern |
| build.distDir | build.frontendDist |
| build.devPath | build.devUrl |
| build.withGlobalTauri | app.withGlobalTauri |
| tauri.windows[].fileDropEnabled | app.windows[].dragDropEnabled |
NEVER skip running npx @tauri-apps/cli migrate -- manual migration is error-prone and the CLI handles most conversions automatically.
NEVER forget to implement update UI -- Tauri v2 removed the automatic update dialog. Without explicit update checking code, users will NEVER receive updates.
NEVER use old import paths after migration -- @tauri-apps/api/tauri is now @tauri-apps/api/core; module-specific APIs moved to plugin packages.
NEVER use "v1Compatible" for createUpdaterArtifacts in new projects -- only use it when migrating existing installations from v1 updater.
ALWAYS restructure for mobile support if targeting mobile -- split main.rs into lib.rs + main.rs with #[cfg_attr(mobile, tauri::mobile_entry_point)].
ALWAYS add core permissions to capabilities -- v2 requires explicit permissions even for core features (windows, events, paths).
| Tauri v1 | Tauri v2 |
|----------|----------|
| Window | WebviewWindow |
| WindowBuilder | WebviewWindowBuilder |
| WindowUrl | WebviewUrl |
| Manager::get_window() | Manager::get_webview_window() |
| v1 Module | v2 Replacement |
|-----------|---------------|
| api::dialog | tauri-plugin-dialog |
| api::http | tauri-plugin-http |
| api::path | Manager::path() methods |
| api::process | tauri-plugin-process |
| api::shell | tauri-plugin-shell |
| v1 Method | v2 Replacement |
|-----------|---------------|
| App::clipboard_manager() | tauri-plugin-clipboard-manager |
| App::get_cli_matches() | tauri-plugin-cli |
| App::global_shortcut_manager() | tauri-plugin-global-shortcut |
| Tauri v1 | Tauri v2 |
|----------|----------|
| @tauri-apps/api/tauri | @tauri-apps/api/core |
| @tauri-apps/api/window | @tauri-apps/api/webviewWindow |
All non-core modules removed from @tauri-apps/api. Install per-plugin packages:
| v1 Import | v2 Plugin Package |
|-----------|------------------|
| @tauri-apps/api/dialog | @tauri-apps/plugin-dialog |
| @tauri-apps/api/fs | @tauri-apps/plugin-fs |
| @tauri-apps/api/http | @tauri-apps/plugin-http |
| @tauri-apps/api/shell | @tauri-apps/plugin-shell |
| @tauri-apps/api/notification | @tauri-apps/plugin-notification |
| @tauri-apps/api/clipboard | @tauri-apps/plugin-clipboard-manager |
| @tauri-apps/api/os | @tauri-apps/plugin-os |
| @tauri-apps/api/process | @tauri-apps/plugin-process |
| @tauri-apps/api/updater | @tauri-apps/plugin-updater |
| Aspect | Tauri v1 | Tauri v2 |
|--------|----------|----------|
| emit() | Emits to specific window | Broadcasts to ALL listeners |
| Targeted emit | N/A | New emit_to() function |
| Global listen | listen_global() | Renamed to listen_any() |
| Window listen | Receives all events | WebviewWindow.listen() only receives events for that specific window |
| Tauri v1 | Tauri v2 |
|----------|----------|
| Menu | MenuBuilder |
| CustomMenuItem | MenuItemBuilder |
| Submenu | SubmenuBuilder |
| MenuItem (predefined) | PredefinedMenuItem |
| SystemTray | TrayIconBuilder |
| Builder::on_menu_event() | App::on_menu_event() or AppHandle::on_menu_event() |
Removed flags:
reqwest-clientreqwest-native-tls-vendoredprocess-command-apishell-open-apiwindows7-compatupdaterlinux-protocol-headerssystem-trayAdded flags:
linux-protocol-body| Feature | Cargo Crate | npm Package |
|---------|-------------|-------------|
| Clipboard | tauri-plugin-clipboard-manager = "2" | @tauri-apps/plugin-clipboard-manager |
| Dialogs | tauri-plugin-dialog = "2" | @tauri-apps/plugin-dialog |
| File System | tauri-plugin-fs = "2" | @tauri-apps/plugin-fs |
| Global Shortcuts | tauri-plugin-global-shortcut = "2" | @tauri-apps/plugin-global-shortcut |
| HTTP | tauri-plugin-http = "2" | @tauri-apps/plugin-http |
| Notifications | tauri-plugin-notification = "2" | @tauri-apps/plugin-notification |
| OS Info | tauri-plugin-os = "2" | @tauri-apps/plugin-os |
| Process | tauri-plugin-process = "2" | @tauri-apps/plugin-process |
| Shell | tauri-plugin-shell = "2" | @tauri-apps/plugin-shell |
| CLI Parsing | tauri-plugin-cli = "2" | @tauri-apps/plugin-cli |
| Updater | tauri-plugin-updater = "2" | @tauri-apps/plugin-updater |
| Feature | Tauri v1 | Tauri v2 |
|---------|----------|----------|
| Desktop support | Yes | Yes |
| Mobile support | No | Yes (iOS + Android) |
| Permission system | Allowlist (boolean flags) | Capabilities + Permissions (fine-grained) |
| Plugin architecture | Monolithic API | Modular plugin packages |
| Menu API | Static builder | Dynamic builder pattern |
| Tray API | SystemTray | TrayIconBuilder |
| Event broadcasting | Per-window default | Global broadcast default |
| IPC Channels | Not available | Channel<T> for streaming |
| Window types | Window only | Window + Webview + WebviewWindow |
| Config format | Nested under tauri key | Flat top-level keys |
| Update dialog | Built-in automatic | Must implement manually |
| Shell open | Built into shell module | Separate opener plugin |
| Binary data IPC | Not optimized | Response type bypasses JSON |
If targeting mobile, restructure the Rust entry point:
Before (v1 style, desktop only):
// src-tauri/src/main.rs
fn main() {
tauri::Builder::default()
.invoke_handler(tauri::generate_handler![])
.run(tauri::generate_context!())
.expect("error running app");
}
After (v2 style, desktop + mobile):
// src-tauri/src/lib.rs
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
tauri::Builder::default()
.invoke_handler(tauri::generate_handler![])
.run(tauri::generate_context!())
.expect("error running app");
}
// src-tauri/src/main.rs (minimal)
fn main() {
app_lib::run();
}
Cargo.toml for mobile:
[lib]
name = "app_lib"
crate-type = ["staticlib", "cdylib", "rlib"]
development
Use when integrating Vite with a backend framework, rendering Vite assets from server-side templates, or setting up dev/production HTML serving. Prevents incorrect manifest.json traversal and missing CSS chunk resolution in production. Covers build.manifest configuration, .vite/manifest.json structure, ManifestChunk properties, dev mode HTML setup, production rendering, CSS/JS chunk resolution, and modulepreload polyfill. Keywords: backend integration, manifest.json, ManifestChunk, Django, Laravel, Rails, modulepreload.
development
Use when encountering dev server startup failures, HMR issues, proxy errors, CORS blocks, or module not found errors during development. Prevents misconfiguring server.hmr behind reverse proxies and forgetting appType: 'custom' in middleware mode. Covers HMR full-reload debugging, proxy configuration, CORS setup, HTTPS certificates, server.fs.strict violations, port conflicts, WebSocket failures, file watcher issues, and middleware mode. Keywords: dev server, HMR, proxy, CORS, HTTPS, WebSocket, port conflict, server.fs.strict, middleware mode, file watcher.
development
Use when encountering pre-bundling errors, dependency resolution failures, stale cache issues, or slow development server startup. Prevents excluding CJS dependencies from pre-bundling (which breaks runtime module resolution) and misconfiguring optimizeDeps. Covers CJS/ESM conversion failures, missing dependency auto-discovery, optimizeDeps configuration, monorepo linked dependencies, cache invalidation, browser cache staleness, and large dependency tree performance. Keywords: pre-bundling, optimizeDeps, CJS, ESM, cache, dependency resolution, monorepo, node_modules/.vite.
development
Use when encountering Vite build failures, chunk size warnings, or version-specific build errors. Prevents the common mistake of using deprecated rollupOptions in v8 or misconfiguring build targets and minifiers. Covers Rolldown/Rollup bundling failures, CSS minification errors, sourcemap problems, library mode build failures, BundleError handling, and asset processing errors. Keywords: build error, Rolldown, chunk size, sourcemap, library mode, minify, BundleError, rollupOptions, build.target.