# The Difference Between tauri-runtime and tauri-runtime-wry in Tauri Architecture

> Understand the difference between tauri-runtime and tauri-runtime-wry. Discover how tauri-runtime defines the webview interface and tauri-runtime-wry provides the WRY and TAO implementation for Tauri apps.

- Repository: [Tauri/tauri](https://github.com/tauri-apps/tauri)
- Tags: internals
- Published: 2026-02-26

---

**tauri-runtime is the abstract trait layer that defines what a runtime must do, while tauri-runtime-wry is the concrete implementation that connects Tauri to the WRY webview engine and TAO windowing system.**

The Tauri framework uses a layered architecture to separate high-level application APIs from low-level system interactions. Understanding the difference between **tauri-runtime** and **tauri-runtime-wry** is essential for developers who want to extend Tauri or understand how it bridges Rust code with native webviews. These two crates work together in the `tauri-apps/tauri` repository to provide the abstraction and implementation that powers every Tauri application.

## What Is tauri-runtime?

**tauri-runtime** acts as the glue layer between the high-level Tauri crates (`tauri`, `tauri-builder`, etc.) and any low-level webview implementation. Located in [`crates/tauri-runtime/src/lib.rs`](https://github.com/tauri-apps/tauri/blob/main/crates/tauri-runtime/src/lib.rs), this crate defines the generic traits that the rest of Tauri uses to stay agnostic of the underlying webview engine.

The core abstractions include:

- **`Runtime`** – The primary trait that any backend must implement
- **`RuntimeHandle`** – A cloneable handle for sending messages to the runtime
- **`WindowDispatch`** – Interface for window-specific operations
- **`WebviewDispatch`** – Interface for webview-specific operations

This crate contains only pure Rust code and depends on utility crates like `serde`, `http`, `raw-window-handle`, and `dpi`. It contains no platform-specific webview code, making it a lightweight dependency for plugins and core libraries that need to reference runtime concepts without pulling in heavy system libraries.

## What Is tauri-runtime-wry?

**tauri-runtime-wry** provides the concrete implementation of the `Runtime` trait for the **WRY** webview library. Found in [`crates/tauri-runtime-wry/src/lib.rs`](https://github.com/tauri-apps/tauri/blob/main/crates/tauri-runtime-wry/src/lib.rs), this crate bridges the abstract `tauri-runtime` interface with the actual `wry` crate (version `0.54.0`) and the `tao` windowing library.

According to the [`ARCHITECTURE.md`](https://github.com/tauri-apps/tauri/blob/main/ARCHITECTURE.md) in the Tauri repository, this crate "opens up direct systems-level interactions specifically for WRY" by implementing the `Runtime` trait for the `Wry<T>` type. It handles platform-specific functionality such as printing, monitor detection, dialog handling, and clipboard operations by forwarding calls to the underlying OS APIs through WRY and TAO.

The [`Cargo.toml`](https://github.com/tauri-apps/tauri/blob/main/Cargo.toml) in [`crates/tauri-runtime-wry/Cargo.toml`](https://github.com/tauri-apps/tauri/blob/main/crates/tauri-runtime-wry/Cargo.toml) declares dependencies on both `wry` and `tauri-runtime` (`path = "../tauri-runtime"`), along with platform-specific crates like `windows`, `gtk`, or `objc2` depending on the target OS.

## Key Architectural Differences

### Abstraction vs. Implementation

**tauri-runtime** declares *what* a runtime must be able to do—create windows and webviews, run tasks on the main thread, query monitors, and handle events—but leaves the *how* to backend implementations. **tauri-runtime-wry** supplies the *how* by creating real `wry::WebView` objects, translating TAO window events into Tauri’s `WindowEvent`, and implementing all platform-specific APIs.

### Dependency Footprint

- **tauri-runtime**: Pure Rust with no platform-specific webview dependencies
- **tauri-runtime-wry**: Heavy dependencies on `wry`, `tao`, and platform-specific system crates

### Usage Patterns

When you call `tauri::Builder::default().run(...)`, you are implicitly using **tauri-runtime-wry** as the default backend. The high-level `tauri` crate imports **tauri-runtime** to maintain agnosticism, while **tauri-runtime-wry** is re-exported and instantiated automatically unless you provide a custom runtime implementation.

## How They Work Together in the Tauri Stack

The separation allows Tauri to support multiple webview backends in theory, though WRY is currently the only official implementation. The [`ARCHITECTURE.md`](https://github.com/tauri-apps/tauri/blob/main/ARCHITECTURE.md) documentation explicitly distinguishes these components: **tauri-runtime** serves as the "glue layer between tauri itself and lower level webview libraries," while **tauri-runtime-wry** provides the "direct systems-level interactions specifically for WRY."

When building a Tauri application, the flow works as follows:

1. Your application code uses `tauri::Builder`, which depends on the abstract `Runtime` trait from **tauri-runtime**
2. At runtime, the builder instantiates the `Wry` struct from **tauri-runtime-wry**, which implements the `Runtime` trait
3. Method calls on the `App` or `Window` types are dispatched through the trait interface to the concrete WRY implementation

## Working with the Runtime Crates

### Using the High-Level API (Default)

Most developers never interact with these crates directly. The default Tauri setup automatically uses **tauri-runtime-wry** behind the scenes:

```rust
use tauri::{Builder, generate_context};

fn main() {
    Builder::default()
        .run(generate_context!())
        .expect("error while running tauri application");
}

```

The `Builder` internally creates a `Wry` runtime, but your code only depends on the abstract `tauri` crate interface.

### Implementing a Custom Runtime

To create a custom backend (for example, targeting a different webview engine), you would implement the traits defined in **tauri-runtime**:

```rust
use tauri_runtime::{
    Runtime, RuntimeHandle, WindowBuilder, WindowEvent, RunEvent, Result,
};

struct MyRuntime;
struct MyHandle;

impl Runtime<()> for MyRuntime {
    type WindowDispatcher = MyWindowDispatcher;
    type WebviewDispatcher = MyWebviewDispatcher;
    type Handle = MyHandle;
    type EventLoopProxy = (); // omitted for brevity

    fn new(_: RuntimeInitArgs) -> Result<Self> { Ok(MyRuntime) }

    // … implement all required methods, delegating to your own webview engine …
}

```

All required methods are defined in [`crates/tauri-runtime/src/lib.rs`](https://github.com/tauri-apps/tauri/blob/main/crates/tauri-runtime/src/lib.rs). By providing a concrete implementation, you could replace the default WRY backend while maintaining compatibility with the Tauri ecosystem.

### Accessing Platform-Specific Features

Some methods, like printing, are implemented specifically in **tauri-runtime-wry** and exposed through the abstract interface:

```rust
use tauri::{Manager, Runtime};

fn print_window<R: Runtime>(app: &tauri::App<R>) {
    // The `print` method is implemented by `tauri-runtime-wry`
    let window = app.get_window("main").unwrap();
    window.print().expect("failed to print");
}

```

The `print` method forwards to the native print dialog via the WRY implementation found in the [`window.rs`](https://github.com/tauri-apps/tauri/blob/main/window.rs) module of **tauri-runtime-wry**.

## Summary

- **tauri-runtime** defines the abstract `Runtime` trait and related interfaces in [`crates/tauri-runtime/src/lib.rs`](https://github.com/tauri-apps/tauri/blob/main/crates/tauri-runtime/src/lib.rs), serving as a platform-agnostic glue layer
- **tauri-runtime-wry** provides the concrete `Wry<T>` implementation in [`crates/tauri-runtime-wry/src/lib.rs`](https://github.com/tauri-apps/tauri/blob/main/crates/tauri-runtime-wry/src/lib.rs), bridging Tauri to the WRY webview and TAO windowing libraries
- The separation allows Tauri core to remain agnostic while enabling pluggable backend implementations
- Default Tauri applications use **tauri-runtime-wry** automatically through `tauri::Builder`
- Custom runtime implementations require implementing the traits defined in **tauri-runtime**

## Frequently Asked Questions

### Can I use tauri-runtime without tauri-runtime-wry?

Yes, if you are building a custom runtime implementation or a plugin that only needs to reference the abstract trait definitions. However, to run an actual Tauri application with a webview, you need a concrete implementation like **tauri-runtime-wry** or your own custom backend that implements the `Runtime` trait.

### What is WRY and how does it relate to tauri-runtime-wry?

**WRY** is the standalone Rust webview library maintained by the Tauri team that wraps native webview engines (WebKit on macOS, WebView2 on Windows, WebKitGTK on Linux). **tauri-runtime-wry** is the adapter crate that implements Tauri's abstract runtime interface using WRY as the underlying engine, effectively translating Tauri API calls into WRY method invocations.

### How do I create a custom runtime implementation?

To create a custom runtime, implement the `Runtime` trait defined in [`crates/tauri-runtime/src/lib.rs`](https://github.com/tauri-apps/tauri/blob/main/crates/tauri-runtime/src/lib.rs) along with its associated types like `WindowDispatcher` and `WebviewDispatcher`. Your implementation must handle event loop management, window creation, and webview instantiation using your chosen backend. This is an advanced use case typically only necessary when integrating Tauri with alternative webview engines or embedded systems.

### Where are the runtime traits defined in the source code?

The core runtime traits—including `Runtime`, `RuntimeHandle`, `WindowDispatch`, and `WebviewDispatch`—are defined in [`crates/tauri-runtime/src/lib.rs`](https://github.com/tauri-apps/tauri/blob/main/crates/tauri-runtime/src/lib.rs) according to the Tauri source code. The concrete implementation for the WRY backend resides in [`crates/tauri-runtime-wry/src/lib.rs`](https://github.com/tauri-apps/tauri/blob/main/crates/tauri-runtime-wry/src/lib.rs).