tao: the window library Tauri maintains because winit would not switch Linux to Gtk
The TAO of cross-platform windowing. A library in Rust built for Tauri.
At a glance
- What is it?
- A Rust crate for creating windows on Windows, macOS, Linux, iOS and Android, forked from winit and built around Gtk on Linux, with the feature flags, Android glue and release cadence that come with living inside the Tauri stack.
- Who is it for?
- Tao makes sense as a dependency for one of two reasons. Either you are building a Tauri application and want the window layer its maintainers already support, or you want a winit-shaped API on Linux without accepting a Wayland-only backend and its consequences.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 2 days ago.
- What is it written in?
- Mainly Rust, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 7, 2026, and from our analysis. They are not legal advice.
Editorial analysis
A windowing crate with a stated reason to exist
The repository description is unusually direct for infrastructure: the TAO of cross-platform windowing, a library in Rust built for Tauri. The README expands it into a capability list, cross-platform application window creation library in Rust that supports all major platforms like Windows, macOS, Linux, iOS and Android, followed by a sentence that tells you the project's entire reason for being separate from its upstream: built for you, maintained for Tauri.
That phrasing does real work. Most people arriving at this crate are arriving through Tauri, and the name itself points at Taoism, the philosophy of simplicity that the project borrows for its brand. But underneath the naming is a fork of winit, and the fork exists for one specific technical reason on one specific platform.
The README states it in a single line under Acknowledgement: this is a fork of winit which replaces Linux's port to Gtk. So the macOS, Windows, iOS and Android paths are inherited winit code, and the Linux path is the divergence. If your application is Linux-only in practice, you may not need this crate at all. If you need a Linux window that works on X11 and Wayland through the same well-trodden toolkit, the reason this fork exists is your reason to use it.
What lives in the tree, including an example suite that documents by demonstration
The repository root is small and conventional: Cargo.toml, Cargo.lock, a LICENSE and a LICENSE.spdx, a README, a CHANGELOG.md, rustfmt.toml, renovate.json, and directories for src, tests, examples, audits, .github and .changes. Two of those are worth naming because they are unusual for a library.
The examples directory is not a token demo. It contains background_color, control_flow, cursor, cursor_grab, custom_events, decorations, drag_window, fullscreen, handling_close, min_max_size, minimize, monitor_list, mouse_wheel, multithreaded, multiwindow, overlay, parentwindow, progress_bar, reopen_event, request_redraw, request_redraw_threaded and resizable. That list is effectively the feature matrix of a window library, expressed as programs you can compile and read. For a crate whose API surface is mostly event callbacks, having twenty focused examples is more useful documentation than a long module reference.
The .changes directory is the other unusual one. It is the shape a changeset-driven release process takes: individual change records accumulated in the repository and turned into version bumps and the CHANGELOG. renovate.json alongside it means dependency updates arrive as automated pull requests, which for a crate with this many platform-specific dependencies is the difference between a maintained library and a stale one.
The Cargo manifest is scoped tightly, with include set to /README.md, src/**/*.rs, examples/**/*.rs and LICENSE*. A crate published to a registry that carries its own examples in the package is making sure its documentation examples still compile for someone reading them on docs.rs rather than only in a git checkout.
Feature flags are where the compatibility decisions are visible
The default feature set is three items, default = ["rwh_06", "x11", "dbus"], and each one is a decision you would otherwise have to infer. rwh_06 selects version 0.6 of the raw-window-handle crate, which is the interop trait connecting a window to graphics APIs, and the alternatives rwh_04 and rwh_05 are still available for downstream crates on older versions. x11 pulls in gdkx11-sys and x11-dl, enabling X11 support on Linux through GTK. dbus pulls in the dbus crate for the Linux desktop bus.
The raw-window-handle situation is the interesting one. The manifest lists rwh_04, rwh_05 and rwh_06 as parallel optional dependencies, all pointing at the same crate name at different versions, with the std feature enabled on the newer two. A library that supports three major versions of its primary integration trait at once is absorbing breakage for its users rather than forcing a coordinated upgrade, which matters most for graphics libraries that move slowly.
The serde feature is the only one the README documents, described as enabling serialization and deserialization of certain types with Serde. In the manifest it expands to dep:serde plus dpi/serde, so the DPI type carries the implementations. Serialising window geometry is the obvious use case: saving and restoring window size and position, including across monitors with different scale factors, is a normal feature for a desktop application and an awkward one to add later.
The documentation metadata is careful in a way that suggests experience with broken docs builds. package.metadata.docs.rs pins the default target to x86_64-unknown-linux-gnu and enumerates four additional targets, and the features list for the docs build includes rwh_04, rwh_05, rwh_06, serde, x11 and dbus, so the rendered documentation shows every feature combination rather than only the defaults.
Linux means installing GTK yourself before anything compiles
The Linux story is the fork's whole reason for being, and the setup requirement is explicit rather than automated. GTK and its related libraries are used to build the support of Linux, and the README says to install the following packages before building, with one command per distribution family.
On Arch Linux and Manjaro:
sudo pacman -S gtk3On Debian and Ubuntu:
sudo apt install libgtk-3-devThe dev suffix on the Debian package matters. Linking against GTK needs headers, and the runtime package alone will not do, so an installation that skips the development package fails at link time with a message that does not obviously point at the missing package.
This is the trade you accept for the fork. winit on Linux can talk to X11 and Wayland through lower-level libraries without dragging in a full toolkit, and the README says Gtk and its related libraries are used to build the support of Linux. In exchange you get a mature widget toolkit path with consistent behaviour across desktops, and behaviour that matches what a GTK application looks like rather than what a custom compositor protocol gives you.
The acknowledgement section also points at where this is heading: in the future, the authors want to make these features more modular as separate crates, so they can switch back to winit and also benefit the whole community. That is an unusually candid statement about a fork's roadmap, and it means the Gtk dependency you install today may become a feature you can drop later.
Android needs a dynamic library target and glue code on main
Android is the platform where the README asks for the most from you, and the two changes it describes are both mechanical once you know them. The library makes use of the ndk-rs crates, and the README refers you to that repository for more documentation rather than duplicating it.
Running on an Android device needs a dynamic system library, so the manifest entry changes:
[[example]]
name = "request_redraw_threaded"
crate-type = ["cdylib"]And the example file gains native activity glue:
#[cfg_attr(target_os = "android", ndk_glue::main(backtrace = "on"))]
fn main() {
...
}The attribute is the interesting part. It rewrites the entry point when the target is Android, and it turns on backtraces, which on a device you cannot attach a debugger to easily is how you get any diagnostic signal at all. The crate-type of cdylib is what the Android build system loads as a shared object rather than as an executable, which is why the ordinary binary target does not work there.
Then the run command, cargo apk run --example request_redraw_threaded, names the example explicitly. This is a real workflow with a real toolchain in front of it, and it is worth setting up early rather than at release time, because the failure modes are in the Android build tooling rather than in the window code.
Release cadence, version policy and the audit trail
Versions here are frequent and the tags are not plain semver. The three most recent releases are tao-v0.37.1 published on 2026-09-26, tao-v0.37.0 on 2026-08-21 and tao-v0.36.0 on 2026-07-29. Three releases in roughly two months on a crate that sits under a whole application framework, and the prefixed tag format means a script that assumes semver tags will not find them.
The Cargo manifest declares version 0.37.1, edition 2021 and rust-version 1.85. A minimum Rust version that recent, on a crate that still supports a 0.0.x era layout at 0.37, tells you the toolchain floor is being moved deliberately and will keep moving. The authors field is also distinctive: Tauri Programme within The Commons Conservancy, and The winit contributors, which reflects the fork's lineage in the attribution itself.
Each release body carries a Cargo Audit transcript rather than prose release notes. The tao-v0.37.1 body opens with a Cargo Audit section that shows the crates.io index update with 361 packages locked, a list of newly added crates including gdkx11-sys, gtk, jni, raw-window-handle and the windows crates, and the advisory database fetch. It then reports scanning Cargo.lock for vulnerabilities across 363 crate dependencies and surfaces findings, starting with the paste crate at version 1.0.15 flagged unmaintained with the title paste, no longer maintained and a date of 2024-10-07.
Publishing that in the release body is unusual and useful. You can see exactly what the audit said on the day of the release, including which transitive dependencies are unmaintained and which newer versions exist but were not taken, which is the sort of information that normally lives in a wiki nobody updates. The cost is that release notes are not a place to read what changed behaviourally, so the CHANGELOG.md and the .changes directory are where that story lives.
Editorial conclusion
Tao makes sense as a dependency for one of two reasons. Either you are building a Tauri application and want the window layer its maintainers already support, or you want a winit-shaped API on Linux without accepting a Wayland-only backend and its consequences. Outside those cases, winit remains the better-known choice with a wider community behind it. Before committing, check three things. Your Rust toolchain needs to be at least 1.85, since that is the declared rust-version. Your Linux build needs GTK 3 development packages installed, which is a system dependency the README is explicit about rather than a build script that fetches it for you. And if you target Android, you need the cdylib example target plus ndk_glue glue on main, which is more setup than any other platform. Read CHANGELOG.md in the repository root, because releases are tagged tao-v0.37.1 style rather than plain semver tags, and the audit output attached to each release is worth a skim before you pin a version. The project is Apache-2.0 licensed with a LICENSE.spdx alongside the LICENSE file, sponsors are collected through Open Collective, and the most recent release and push both landed on 2026-09-26.
Frequently asked questions
What platforms are Tauri compatible with?
The windowing crate under Tauri supports Windows, macOS, Linux, iOS and Android. On Linux it uses GTK, which means installing GTK 3 development packages before building, with sudo pacman -S gtk3 on Arch or Manjaro and sudo apt install libgtk-3-dev on Debian or Ubuntu. Android additionally needs an example target built as a cdylib plus ndk_glue glue on the main function.
How is tao different from winit?
Tao is a fork of winit that replaces the Linux port with GTK, and the README states the reason: in the future the authors want to make these features more modular as separate crates so they can switch back to winit. Everything else, including the Windows, macOS and Android paths, is inherited from winit. The Cargo manifest still credits The winit contributors and still offers feature flags for raw-window-handle versions 0.4, 0.5 and 0.6.
What is the minimum Rust version for tao?
The Cargo manifest declares rust-version 1.85 with edition 2021. The crate is published under Apache-2.0 and the current version is 0.37.1, released on 2026-09-26 under the tag tao-v0.37.1. The nonstandard tag prefix matters if you track releases automatically, since a script looking for plain semver tags will not match.
How do I run a tao example on Android?
Add an example entry to Cargo.toml with crate-type set to cdylib, annotate main with a cfg_attr that applies ndk_glue::main with backtraces on for Android targets, and run cargo apk run naming the example. The README's example is request_redraw_threaded. The underlying Android work uses the ndk-rs crates, whose repository the README points to for further detail.
Does tao support serialising window state?
There is a serde feature, documented in the README as enabling serialization and deserialization of certain types with Serde. In the Cargo manifest it expands to dep:serde together with dpi/serde, so the DPI types carry the implementations. That is what lets you save and restore window size and position, which matters on systems with mixed display scale factors.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/tauri-apps-tao)