# PyTauri, Tauri bindings for Python that avoid the IPC round trip

> PyTauri puts Python inside a Tauri desktop application through Pyo3, so a Python command runs in the same process as the Rust side rather than over a message channel. The result is a Tauri app where the business logic is Python, the IPC client is generated for you, and the type stubs are complete enough for pyright to call the API fully typed.

**pytauri/pytauri** — Tauri binding for Python through Pyo3

- Repository: https://github.com/pytauri/pytauri
- Website: https://pytauri.github.io/pytauri/
- Stars: 1,437 · Forks: 30
- Language: Rust
- License: Apache-2.0
- Published: 2026-10-16 · Updated: 2026-10-16 · Language: en
- Canonical page: https://hysenlabs.com/projects/pytauri-pytauri

## Why not just write the command in Rust

The positioning is one line in the feature list: you need a Rust compiler, but almost do not need to write Rust code. The alternative stated in the same list is pytauri-wheel, where you will not need the Rust compiler at all and everything can be done in Python, with a separate example directory for that route. The technical claim underneath is the one that matters: no IPC overhead, secure and fast, thanks to Pyo3. A conventional Tauri app calls the Rust side over an inter-process channel, and that channel has a cost per call, plus a serialization step and a trust boundary you have to reason about. Here the Python code is embedded in the host process through Pyo3, so a command call is a function call. The repository is written in Rust, the licence is Apache-2.0, the documentation is at pytauri.github.io, and the project describes itself as a completely free and open-source project that is difficult to maintain without incentives and contributions from the community.

```python
import sys

from pydantic import BaseModel
from pytauri import (
    AppHandle,
    Commands,
)
from pytauri_plugins.notification import NotificationExt

commands: Commands = Commands()


class Person(BaseModel):
    name: str
```

## Commands, and the shape of the Python API

The Python side mirrors the Tauri Rust API as closely as possible, and the example shows how that works in practice. You instantiate a Commands object, then decorate a function with the command decorator, and the function's arguments and return value are ordinary Python types. Here the argument is a pydantic model, Person, with a name field, and the return value is another pydantic model, Greeting, with a message field. The function is async, and it takes an AppHandle, which is how a Python command reaches the Tauri application handle to do things like show a notification. The notification example uses the plugin extension class to build and show one. The point of the pydantic models is that the request payload and the response payload are structured and validated on the Python side, rather than being untyped dictionaries that cross the boundary and fail somewhere else.

```python
@commands.command()
async def greet(body: Person, app_handle: AppHandle) -> Greeting:
    notification_builder = NotificationExt.builder(app_handle)
    notification_builder.show(title="Greeting", body=f"Hello, {body.name}!")

    return Greeting(
        message=f"Hello, {body.name}! You've been greeted from Python {sys.version}!"
    )
```

## The frontend side, and the generated IPC client

The TypeScript side gets a generated client rather than a hand-written one. The frontend example imports pyInvoke from the tauri-plugin-pytauri-api package, with the alternative noted that it is also available as window.__TAURI__.pytauri. The interfaces for the request and response types are declared in TypeScript, and the call is a single awaited invocation. Because the client and the types are generated from the Python definitions rather than written by hand, the two sides cannot drift, and the generator is described as automatically generating TypeScript types and client for IPC. The project claims 100 percent type completeness, measured against pyright's typed-libraries scale, and that claim is specific enough to be checked: it means the Python API is annotated so completely that a type checker has nothing to complain about, which is a meaningful bar for a library whose whole surface crosses a language boundary.

```ts
import { pyInvoke } from "tauri-plugin-pytauri-api";
// or: `const { pyInvoke } = window.__TAURI__.pytauri;`

export interface Person {
    name: string;
}
```

## The wheel route, and what it changes

The distribution story is the part most people will care about, because it decides what a user has to install. The plain route needs a Rust compiler, because the Python bindings are compiled into the Tauri application. The wheel route, pytauri-wheel, packages things so that you do not need the Rust compiler, and there is a separate example directory for it, examples/tauri-app-wheel, next to the ordinary examples/tauri-app. The release table shows that pytauri-wheel is published to PyPI while the core and the plugin are published to crates.io and npm. There is also a mention of using Cython to protect your source code, which is a real consideration for anyone shipping a closed-source desktop app in Python, since by default the Python source travels with the application and is readable. The other end of the distribution story is packaging: it can be integrated with tauri-cli to build and package standalone executables, so the output is a normal installer rather than something a user has to run with a Python interpreter.

```
pytauri-wheel
pytauri
pytauri-core
tauri-plugin-pytauri
tauri-plugin-pytauri-api
```

## Plugins, and building your own

PyTauri does not reimplement the Tauri plugin ecosystem, it reuses it. The feature list says it supports Tauri official plugins, with the notification plugin as the example shown, and that you can write your own plugins. The Cargo manifest confirms the scale of that ecosystem in the dependency list, with entries for the opener, the clipboard manager, the dialog, the filesystem, the notification, the autostart, the deep link, the upload, the websocket, the http, the os, the persisted scope, the positioner, the process, the shell, the single instance, the updater, the window state and the global shortcut plugins. Each is a versioned dependency on the official crate, which is the right way to build this: the Python side extends, it does not fork. The project also notes that the API is ergonomic and as close as possible to the Tauri Rust API, which is what makes the mental model transfer for someone who has written a Tauri app in Rust.

```
tauri-plugin-notification
tauri-plugin-dialog
tauri-plugin-fs
tauri-plugin-shell
tauri-plugin-http
tauri-plugin-updater
```

## Async, and the Python-native web stack

Two features change what an application can look like. The first is native async support, with asyncio, trio and anyio all supported, which matters because a Tauri command that awaits an HTTP call should not block the event loop, and because the three libraries cover very different async styles. The second is that PyTauri can be integrated with nicegui, gradio and FastAPI to achieve a full-stack Python development experience, without Node.js at all, with the examples/nicegui-app directory demonstrating it. That is a broader claim than just calling Python from Rust. It says you can build a desktop application where the interface is a Python web framework and the shell is Tauri. The README calls this out as a way to achieve a full-stack Python experience, and the example directory is the place to check whether it fits your project.

```
asyncio
trio
anyio
nicegui
gradio
FastAPI
```

## The workspace, and how the pieces are versioned

The repository is a multi-language workspace, and the manifests show how it is held together. The Cargo workspace includes the crates directory, the Tauri application of the main example, the nicegui example, a test crate and the Python wheel project, with the resolver set to 2 and the Rust edition at 2021 with a minimum Rust version of 1.82. The Pyo3 family is pinned at 0.25, and Tauri itself at 2.8 with the build and plugin crates at 2.4. The Python side is a uv workspace with the same idea: the pyproject lists dependency groups for dev, lint, docs, test, tools, build-system, workspaces and examples, and the workspaces group enumerates the member directories. The version policy is stated in the release section: they follow Semantic Versioning 2.0.0, and Rust and its Python bindings, PyTauri core and its plugins will keep the same MAJOR.MINOR version number. That is a strong promise for a multi-language project and it is the thing to check when a release lands.

```toml
[workspace.package]
version = "0.1.0"
edition = "2021"
license = "Apache-2.0"
rust-version = "1.82"
```

## Where the boundary sits, and the release state

Three things to weigh before adopting. The first is that the binding layer is real complexity, and the claim of no IPC overhead comes with a cost in build tooling, in the need to keep Rust and Python type definitions in step, and in a debugging story that spans two languages. The second is the maintenance honesty in the project documentation, which says plainly that it is difficult to maintain without incentives and contributions from the community, and the release history supports reading that carefully. The most recent releases are v0.8.0 on 2025-09-02 for the Python package, with matching rs/pytauri and rs/tauri-plugin-pytauri tags the day before, and the repository itself was last pushed on 2026-10-15 and is not archived. So the code is being worked on, but the published version line is over a year old in the visible history. The third is the type completeness claim, which is verifiable and worth verifying, since a binding library whose stubs are incomplete is a binding library you will fight.

```
crates/
docs/
examples/
python/
utils/
```

## Conclusion

Adopt PyTauri if you want a Tauri desktop application whose logic is written in Python, especially if your team already has a Python codebase or a Python-native UI framework, and skip it if you want a pure Rust Tauri app with a thin web frontend, because the binding layer adds a build step and a Python runtime. Verify three things before you commit: which distribution route you take, since the wheel route removes the Rust compiler requirement and the plain route does not; that the async story works for your code, since the project supports asyncio, trio and anyio natively; and the version alignment, because the Rust crate, the PyTauri core, the plugins and the Python packages share a MAJOR.MINOR number and are released together.

## FAQ

### What is PyTauri and how does it talk to Python?

It is a set of Tauri bindings for Python through Pyo3. The claim is that there is no inter-process communication overhead, because the Python code runs in the same process as the Rust side rather than over a message channel.

### Do I need a Rust compiler to use PyTauri?

For the normal route, yes: you need a Rust compiler, but almost do not need to write Rust code. The pytauri-wheel route removes the compiler requirement so everything can be done in Python, and the repository has a separate example directory for that case.

### How does the Python side define commands?

You instantiate a Commands object and decorate an async function with the command decorator, using ordinary Python types such as pydantic models for the request body and the return value, and taking an AppHandle to reach the Tauri application.

### Can I use PyTauri with a Python web framework instead of a TypeScript frontend?

Yes. The project says it can be integrated with nicegui, gradio and FastAPI to achieve a full-stack Python development experience without Node.js, and it ships an example under examples/nicegui-app.

## Sources

- [License: Apache-2.0](https://github.com/pytauri/pytauri/blob/main/LICENSE)
- [Project website](https://pytauri.github.io/pytauri/)
- [pytauri/pytauri on GitHub](https://github.com/pytauri/pytauri)
- [README](https://github.com/pytauri/pytauri/blob/main/README.md)
- [Releases](https://github.com/pytauri/pytauri/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/pytauri-pytauri
