tauri-async-windows

star 0

Patterns for deadlock-free multi-window management in Tauri

PaperPlaneLabs By PaperPlaneLabs schedule Updated 3/7/2026

name: tauri-async-windows description: Patterns for deadlock-free multi-window management in Tauri

Tauri Async Multi-window Management

This skill covers the best practices for creating and managing multiple windows in a Tauri application to avoid deadlocks and maintain a clean SPA architecture.

1. Async Command Pattern

The Problem

If a Tauri command that creates a window (using WebviewWindowBuilder) is synchronous (pub fn), it runs on the main thread. However, WebviewWindowBuilder::build() often needs to dispatch work to the main thread. This leads to a deadlock where the command is waiting for the main thread, but the main thread is blocked by the command.

The Solution: async fn

Always define window-creating commands as async. This allows Tauri to run them on a background thread pool, leaving the main thread free to handle the window construction.

// BAD: Synchronous command causing deadlock
#[tauri::command]
pub fn open_window(app: AppHandle) {
    WebviewWindowBuilder::new(&app, "label", Default::default()).build().unwrap();
}

// GOOD: Asynchronous command
#[tauri::command]
pub async fn open_window(app: AppHandle) -> Result<(), String> {
    WebviewWindowBuilder::new(&app, "label", Default::default())
        .build()
        .map_err(|e| e.to_string())?;
    Ok(())
}

2. SPA Label-Based Routing

Instead of loading separate HTML files for different windows, use the main SPA (index.html) and render different UI components based on the window's label.

Backend Setup

Use Default::default() for the URL in the builder. This points to the application's root (index.html).

WebviewWindowBuilder::new(&app, "break", Default::default())
    .title("Break Reminder")
    .build()

Frontend Implementation (Svelte 5 Example)

In your main +page.svelte (or entry point), check the window label on mount or dynamically via $state.

// app.d.ts
interface Window {
  __TAURI_INTERNALS__?: {
    metadata?: {
      currentWindow?: {
        label: string;
      };
    };
  };
}

// +page.svelte
const isBreakWindow = $derived(
  window.__TAURI_INTERNALS__?.metadata?.currentWindow?.label === "break"
);
{#if isBreakWindow}
  <BreakView />
{:else}
  <MainAppUI />
{/if}

3. Window Positioning

Always use logical coordinates and account for scale factors when positioning windows programmatically to ensure they appear centered or correctly docked on high-DPI displays.

Install via CLI
npx skills add https://github.com/PaperPlaneLabs/MyTodos --skill tauri-async-windows
Repository Details
star Stars 0
call_split Forks 0
navigation Branch main
article Path SKILL.md
More from Creator
PaperPlaneLabs
PaperPlaneLabs Explore all skills →