Skip to content

Dioxus v0.7.0

Latest

Choose a tag to compare

@ealmloff ealmloff released this 31 Oct 04:49
· 3 commits to main since this release

Hot-Patching, Native Renderer, Axum Integration, Bundle Splitting, Radix-UI, more!

Welcome back to another Dioxus release! Dioxus (dye • ox • us) is a framework for building cross-platform apps in Rust. We make it easy to ship full-stack web, desktop, and mobile apps with a single codebase.

Dioxus 0.7 delivers on a number of promises we made to improve Rust GUI, and more broadly, what we call “high level Rust.” Rust has excelled as a tool for building foundational software, but we hope with Dioxus 0.7, it’s one step closer to being suitable for rapid, high-level development.

In this release, we’re shipping some incredible features. The highlights of this release include:

  • Subsecond: Hot-patching of Rust code at runtime
  • Dioxus Native: WGPU-based HTML/CSS renderer for Dioxus
  • Fullstack: Revamp of Server Functions with full Axum integration
  • WASM-Split: Code splitting and lazy loading for WebAssembly
  • Stores: A new primitive for nested reactive state
  • Dioxus Primitives: first-party radix-primitives implementation for Dioxus

Dioxus 0.7 also brings a number of other exciting new features:

  • Automatic tailwind: zero-setup tailwind support built-in!
  • LLMs.txt: first-party context file to supercharge AI coding models
  • Blitz: our modular HTML/CSS renderer powering Dioxus Native, available for everyone!
  • Fullstack WebSockets: websockets in a single line of code
  • Integrated Debugger Support: open CodeLLDB with a single keystroke
  • Fullstack error codes: Integration of status codes and custom errors in fullstack
  • Configurable Mobile Builds: Customize your AndroidManifest and Info.plist

Plus, a number of quality-of-life upgrades:

  • one-line installer ( curl https://dioxus.dev/install.sh | sh )
  • dx self-update and update notifications
  • automatically open simulators
  • Improved log coloring
  • desktop and mobile toasts
  • HTML streaming now waits for the router to render
  • Axum 0.8 and Wry 52 upgrade
  • Android + iOS device support
  • More customization of iOS and Android projects
  • Hash Router Support for dioxus-web
  • Multi-package serve: dx serve @client --package xyz @server --package xyz
  • Support for dyib bundling
  • wasm32 support for fullstack
  • Hashless assets
  • /public dir
  • And many, many bugs fixed!

Rust Hot-patching with Subsecond

The biggest feature of this release: Dioxus now supports hot-patching of Rust code at runtime! You can now edit your Rust code and see changes without losing your app’s state.

We’ve been working on this feature for almost an entire year, so this is a very special release for us. The tool powering this hot-patching is called Subsecond and works across all major platforms: Web (WASM), Desktop (macOS, Linux, Windows), and even mobile (iOS, Android):

hotpatch-android.mp4
ios-binarypatch.mp4

You can now iterate on your app’s frontend and backend simultaneously without skipping a beat.

hotpatch-wasm-complete.mp4

Subsecond works in tandem with the Dioxus CLI to enable hot-patching for any Rust project. Simply run dx serve on your project and all subsecond::call sites will be hot-patched. For example, here’s Subsecond working with a Ratatui app:

subsecond-tui.mp4

The infrastructure to support Subsecond is quite complex. Currently, we plan to only ship the Subsecond engine within the Dioxus CLI itself with a long-term plan to spin the engine out into its own crate. For now, we still want the ecosystem to experience the magic of Subsecond, so we’ve made the CLI compatible with non-dioxus projects and removed “dioxus” branding when not serving a dioxus project.

Screenshot_2025-06-24_at_1 49 07_PM

Hot-patching Rust code is no simple feat. To achieve a segfault-free experience, we recommend framework authors to tie into Subsecond’s minimal runtime. For application developers, you can simply use subsecond::call(some_fn) at clean integration points to take advantage of hot-patching. If you use Dioxus, hot-patching comes directly integrated with components and server functions.

pub fn launch() {
    loop {
        std::thread::sleep(std::time::Duration::from_secs(1));
        subsecond::call(|| tick());
    }
}

fn tick() {
    println!("edit me to see the loop in action!!!!!!!!! ");
}

While in theory we could implicitly override calls to tick with function detouring, we instead chose explicit integration points. The first version of subsecond modified process memory externally, but we struggled with issues where the program would be stuck in a task with no way to “resurface”. For this example, the program would always be waiting for IO, making our edits not take effect:

fn main() {
    loop {
        let next_event = wait_for_io();
        do_thing();
    }
}

Instead, the explicit runtime integration provides a simple “synchronization point” where the framework can handle things like closing TCP connections, re-instancing state, dropping event listeners, etc. If you add or remove a field of a struct between hot-patches, Subsecond does not automatically migrate your state for you. Libraries like bevy-reflect make this easier - and we might integrate reflection at some point - but for now, frameworks should take care to either dispose or safely migrate structs that change.

We expect folks to use Subsecond outside of Dioxus, namely in web development, so we’ve provided a few starter-integrations for popular libraries:

  • Axum
  • Bevy
  • Ratatui

Subsecond has already made its way into popular projects like Bevy and Iced. Right now, you can git pull the latest Bevy and Iced repositories and start hot-patching with zero setup:

bevy-hotpatch.mp4

Hot-patching covers nearly every case in Dioxus. Many tasks that were previously massively burdensome are now a breeze:

  • Adding a new asset!() call
  • Editing strongly-typed interfaces on components like icon variants or links
  • Dynamically adding children to a component
  • Modifying backend server function code
  • Modifying event handler logic - ie onclick or onmouseover
  • Loading resources and async values
  • Refactoring rsx into components

Under the hood, we implemented a form of incremental linking / binary patching tailored for running apps. This is not too distant from the idea laid out by Andrew Kelley for Zig.

Dioxus Native and Blitz

We’re extremely excited to announce the first-ever version of Dioxus Native: our new renderer that paints Dioxus apps entirely on the GPU with WGPU.

Out of the box, it already supports a huge number of features

  • Accessibility integration
  • Event handling
  • Asset fetching and loading.

Dioxus Native required a monumental amount of work, pushing forward

  • HTML/CSS layout and rendering
  • High quality text painting

We’re extremely excited to release Blitz: our modular HTML/CSS rendering engine.

Blitz combines a number of exciting projects to bring customizable HTML rendering engine to everyone. Blitz is a result of collaboration across many projects: Firefox, Google, Servo, and Bevy. We’re leveraging a number of powerful libraries:

  • Taffy: our high-performance flexbox layout engine
  • Stylo: Firefox and Servo’s shared CSS resolution engine
  • Vello: Linebender’s GPU compute renderer

Blitz is an extremely capable renderer, often producing results indistinguishable from browsers like Chrome and Safari:

blitzvssafari

Not every CSS feature is supported yet, with some bugs like incorrect writing direction or the occasional layout quirk. Our support matrix is here: https://blitz.is/status/css

The samples that Blitz can create are quite incredible. Servo’s website:

image

Hackernews:

image 1

The BBC:

Screenshot_2025-03-29_at_2 04 28_PM

We even implemented basic <form /> support, making it possible to search Wikipedia without a full browser:

Screen_Recording_2025-05-24_at_16.21.05.mov

Do note that Blitz is still very young and doesn’t always produce the best outputs, especially on pages that require JavaScript to function properly or use less-popular CSS features:

Screenshot_2025-03-29_at_2 09 14_PM

Blitz also provides a pluggable layer for interactivity, supporting actions like text inputs, pluggable widgets, form submissions, hover styling, and more. Here’s Dioxus-Motion working alongside our interactivity layer to provide high quality animations:

Screen_Recording_2025-01-05_at_7.46.14_PM.mov

Bear in mind that Blitz is still considered a “work in progress.” We have not focused on performance

Dioxus Fullstack Overhaul

We completely revamped Dioxus Fullstack, bringing in a new syntax and a whole host of new features.

To start, we've introduced a new dioxus::serve entrypoint for server apps that enables hot-patching of axum routers:

combined-fullstack-hotpatch.mp4

The new syntax upgrades makes it easy to declare stable endpoints with a syntax inspired by the popular Rocket library.

/// you can now encode query and path parameters in the macro!
#[get("/api/{name}/?age")]
async fn get_message(name: String, age: i32) -> Result<String> {
    Ok(format!("Hello {}, you are {} years old!", name, age))
}

This revamp allows you to use any valid Axum handler as a Dioxus Server Function, greatly expanding what bodies are allowed. This introduces a number of useful utilities like:

  • Server Sent Events with ServerEvents<T> type
  • Websocket and use_websocket for long-lived bidirectional communication
  • Streaming<T> for arbitrary data streams
  • Typed Form<T> type and MultipartFormData for handling forms
  • FileStream for streaming uploads and downloads

An example of the new APIs in example is this simple websocket handler:

#[get("/api/uppercase_ws?name&age")]
async fn uppercase_ws(
    name: String,
    age: i32,
    options: WebSocketOptions,
) -> Result<Websocket<ClientEvent, ServerEvent, CborEncoding>> {
    Ok(options.on_upgrade(move |mut socket| async move {
        // send back a greeting message
        _ = socket
            .send(ServerEvent::Uppercase(format!(
                "Fist message from server: Hello, {}! You are {} years old.",
                name, age
            )))
            .await;

        // Loop and echo back uppercase messages
        while let Ok(ClientEvent::TextInput(next)) = socket.recv().await {
            _ = socket.send(ServerEvent::Uppercase(next)).await;
        }
    }))
}

Paired with the use_websocket hook, you can easily send and receive messages directly from your frontend.

fn app() -> Element {
    // Track the messages we've received from the server.
    let mut messages = use_signal(std::vec::Vec::new);

    // The `use_websocket` wraps the `WebSocket` connection and provides a reactive handle to easily
    // send and receive messages and track the connection state.
    let mut socket = use_websocket(|| uppercase_ws("John Doe".into(), 30, WebSocketOptions::new()));

    // Calling `.recv()` automatically waits for the connection to be established and deserializes
    // messages as they arrive.
    use_future(move || async move {
        while let Ok(msg) = socket.recv().await {
            messages.push(msg);
        }
    });

    rsx! {
        h1 { "WebSocket Example" }
        p { "Type a message and see it echoed back in uppercase!" }
        p { "Connection status: {socket.status():?}" }
        input {
            placeholder: "Type a message",
            oninput: move |e| async move { _ = socket.send(ClientEvent::TextInput(e.value())).await; },
        }
        button { onclick: move |_| messages.clear(), "Clear messages" }
        for message in messages.read().iter().rev() {
            pre { "{message:?}" }
        }
    }
}

An example of websockets in action:

fullstack-websockets-with-frame.mp4

Dioxus Primitives - a collection of Radix-UI equivalents

You asked, we listened. Dioxus now has a first-party component library based on the popular JavaScript library, Radix-Primitives. Our library implements 28 foundational components that you can mix, match, customize, and restyle to fit your project. Each component comes unstyled and is fully equipped with keyboard-shortucts, ARIA accessibility, and is designed to work seamlessly across web, desktop and mobile.

Screen_Recording_2025-08-05_at_10.12.14_AM.mov

In addition to the unstyled primitives, the components page includes a shadcn-style version of each primitive with css you can copy into your project to build a component library for your project. You can combine these primitives to create larger building blocks like cards, dashboards and forms.

Screenshot_2025-08-05_at_9 58 36_AM

The community has already started construction on new component variants with an exciting project called Lumenblocks built by the Leaf Computer team.

Screenshot_2025-06-27_at_5 13 46_PM

Stores - a new primitive for nested reactive state

We introduced signals in 0.5 to enable fine grained reactive updates in dioxus. Signals are great for atomic piece of state in a component like a string or number, but they are difficult to use with external or nested state. Stores are a powerful new primitive for nested reactive state in 0.7.

With stores, you can derive a store trait on your data to let you zoom into specific parts of the state:

#[derive(Store)]
struct Dir {
    children: BTreeMap<String, Dir>,
}

// You can use the children method to get a reactive reference to just that field
let mut children: Store<Vec<Dir>, _> = directory.children();

Stores also include implementations for common data structures like BTreeMap that mark only the changed items as dirty for each operation:

#[component]
fn Directory(directory: Store<Dir>) -> Element {
    // Create a temporary to reference just the reactive child field
    let mut children = directory.children();
    rsx! {
        ul {
            // Iterate through each reactive value in the children
            for (i, dir) in children.iter().enumerate() {
                li {
                    key: "{dir.path()}",
                    div {
                        display: "flex",
                        flex_direction: "row",
                        "{dir.path()}",
                        button {
                            onclick: move |_| {
                                children.remove(i);
                            },
                            "x"
                        }
                    }
                    Directory { directory: dir }
                }
            }
        }
    }
}

When we remove a directory from the store, it will only rerun the parent component that iterated over the BTreeMap and the child that was removed.

Untitled_(1)

Automatic Tailwind

The community has been asking for automatic Tailwind for a very long time. Finally in Dioxus 0.7, dx detects if your project has a tailwind.css file at the root, and if it does, automatically starts a TailwindCSS watcher for you. You no longer need to manually start or download the Tailwind CLI - everything is handled for you seamlessly in the background:

tailwind-inline.mp4

We’ve updated our docs and examples to Tailwind V4, but we’ve also made sure the CLI can handle and autodetect both V3 and V4. Automatic Tailwind support is an amazing feature and we’re sorry for not having integrated it earlier!

Improvements with AI - LLMs.txt and “vibe-coding”

If you’ve kept up with the news recently, it’s become obvious that AI and Large Language Models are taking over the world. The AI world moves quickly with new tools and improvements being released every week. While the reception of LLMs in the Rust community seems to be mixed, we don’t want Dioxus to be left behind!

In Dioxus 0.7, we’re shipping our first step in the AI world with a first-party llms.txt automatically generated from the Dioxus documentation! LLMs can easily stay up to date on new Dioxus features and best practices, hopefully reducing hallucinations when integrating with tools like Copilot and Cursor.

The latest version of the template also includes an optional set of prompts with context about the latest release of dioxus. The prompts provide condensed information about dioxus for tools that don’t have access to web search or llms.txt integration.

Combined with the Subsecond hot-patching work, users can now more effectively “vibe code” their apps without rebuilding. While we don’t recommend “vibe coding” high-stakes parts of your app, modern AI tools are quite useful for quickly whipping up prototypes and UI.

vibe-code-2.mp4

WASM Bundle Splitting and Lazy Loading

bundle-split.mp4

Integrated Debugger

To date, debugging Rust apps with VSCode hasn’t been particularly easy. Each combination of launch targets, flags, and arguments required a new entry into your vscode.json With Dioxus 0.7, we wanted to improve debugging, so we’re shipping a debugger integration! While running dx serve, simply press d and the current LLDB instance will attach to currently running app. The new debugger integration currently only works with VSCode-based editor setups, but we’d happily accept contributions to expand our support to Neovim, Zed, etc.

debugger-dx.mp4

The integrated debugger is particularly interesting since it works across the web, desktop, and mobile. Setting up an Android debugger from VSCode is particularly challenging, and the new integration makes it much easier.

debug-android-vscode.mp4

When launching for the web, we actually open a new Chrome instance with a debugger attached. Provided you download the DWARF symbols extension, Rust symbols will show up properly demangled in the debugger tab instead of confusing function addresses.

debugger-web.mp4

Various Quality of Life Upgrades

We’ve shipped a number of quality-of-life upgrades that don’t necessarily warrant their own section in the release notes.

Now, when you launch a mobile app, dx will automatically open the iOS and Android simulator:

auto-launch.mp4

Desktop and mobile now have the same development-mode toasts:

mobile-toast.mp4

The log coloring of the CLI and help menus have been upgraded to match cargo and reflect error/warn/debug/info levels:

Screenshot_2025-06-27_at_7 40 49_PM

DX Compatibility with any project

The dioxus CLI “dx” tooling is now usable with any Rust project, not just Dioxus projects! You can use dx alongside any Rust project, getting a number of awesome features for free:

  • Rust hot-reloading with Subsecond
  • Packaging and bundling for Web/Desktop/Mobile
  • Extraction and optimization of assets included with the asset!() macro
  • Interactive TUI with shortcuts to rebuild your app
  • Tracing integration to toggle “verbose” and “tracing” log levels
  • Simultaneous multi-package dx serve @client @server support
  • Integrated debugger

Notably, Bevy has already integrated support for Subsecond and works well with the new dx:

bevy-scad_.online-video-cutter.com.mp4

We have big plans for dx and will improve it by adding support for more features:

  • Remote build caching for instant fresh compiles
  • Advanced caching for incremental builds in CI
  • Dedicated Docker and GitHub images for cross-platform distribution
  • Adapters to make your project usable with Bazel / Buck2
  • Built-in deploy command for deploying to AWS/GCP/Azure/Cloudflare
  • Integrated #[test] and #[preview] attributes that work across web, desktop, and mobile
  • Inline VSCode Simulator support
  • Detailed build timings for cargo and bundling
  • CI integration with integrated dashboard

Improved Version Management Experience

Dioxus has supported binary installation for quite a while - but we’ve always required users to install cargo binstall and then run cargo binstall dioxus-cli. Now, we’re dropping the cargo binstall requirement entirely, making it easy to install the CLI and then keep it updated.

To install the CLI:

curl -fsSL https://dioxus.dev/install.sh | bash

Whenever the Dioxus team pushes new updates, the CLI will automatically give you a one-time update notification. To update, you can use

dx self-update
Screenshot_2025-06-27_at_7 25 50_PM

When you try to use the dioxus-cli with an incompatible dioxus version, you’ll receive a warning and some instructions on how to update.

Screenshot_2025-06-27_at_7 19 47_PM

Customize AndroidManifest.xml and Info.plist

You can now customize the Info.plist and AndroidManifest.xml files that Dioxus generates for your Android, iOS, and macOS projects. This makes it possible to add entitlements, update permissions, set splash screens, customize icons, and fully tweak your apps for deployment.

ADB Reverse Proxy for Device Hot-Reload

Thanks to community contributions, dx serve --platform android now supports Android devices! You can edit markup, modify assets, and even hot-patch on a real Android device without needing to boot a simulator. This works by leveraging adb reverse, and should help speed up Android developers looking to test their apps on real devices.

iPad Support

A small update - Dioxus now properly supports iPad devices! When you dx serve --platform ios with an iPad simulator open, your Dioxus app will properly scale and adapt to the iPadOS environment.

Screenshot_2025-06-27_at_6 00 29_PM

Basic Telemetry

  • Anonymized by default
  • Using it to hunt down panics in tooling and in dioxus itself (during development)
  • Want to provide more robust library and tooling - github issues only captures a snapshot
  • Opt out

Over time, the CLI has grown from a simple server that watches for file changes and reruns cargo to a tool that helps you through every stage of your apps lifecycle with support for bundling, asset optimization, hot patching, hot reloading, and translation. As the complexity has grown, so has the surface area for bugs and UX issues. To make the CLI more robust, we have started collecting a minimal set of telemetry data in 0.7. This information will help to catch rare panics, performance issues and trends over time that don’t show up in github issues. All telemetry is anonymized with all personal information stripped. We collect:

  • Commands invoked without args (eg. dx serve --hot-patch --profile <stripped> --package <stripped>)
  • Timing information for each build state (eg. asset optimization: 2s, linking: 1s, wasm-bindgen: 4s)
  • Panics and errors from the CLI with all paths stripped (eg. unwrap() at <stripped>/cli/src/build.rs )
  • An unique identifier based on a hash of your system information (eg. HARDWARE_ID=218853676744316928865703503826531902998)
  • Your target triple, dx version and if you are running in CI: (eg. TRIPLE=arch64-apple-darwin CI=false DX=0.7.0-alpha.3 )

For reference, here is a snippet of the telemetry collected over the last week on my installation:

{"identity":{"device_triple":"aarch64-apple-darwin","is_ci":false,"cli_version":"0.7.0-alpha.3 (ba856ac)","session_id":218853676744316928865703503826531902998},"name":"cli_command","module":null,"message":"serve","stage":"start","time":"2025-07-24T14:34:07.684804Z","values":{"args":{"address":{"addr":null,"port":null},"always_on_top":null,"cross_origin_policy":false,"exit_on_error":false,"force_sequential":false,"hot_patch":false,"hot_reload":null,"interactive":null,"open":null,"platform_args":{"client":null,"server":null,"shared":{"args":false,"targets":{"build_arguments":{"all_features":false,"base_path":false,"bin":null,"bundle":null,"cargo_args":false,"debug_symbols":true,"device":false,"example":false,"features":false,"inject_loading_scripts":true,"no_default_features":false,"package":null,"platform":null,"profile":false,"release":false,"renderer":{"renderer":null},"rustc_args":false,"skip_assets":false,"target":null,"target_alias":"Unknown","wasm_split":false},"fullstack":null,"ssg":false}}},"watch":null,"wsl_file_poll_interval":null}}}
{"identity":{"device_triple":"aarch64-apple-darwin","is_ci":false,"cli_version":"0.7.0-alpha.3 (ba856ac)","session_id":218853676744316928865703503826531902998},"name":"build_stage","module":null,"message":"Build stage update","stage":"installing_tooling","time":"2025-07-24T14:34:08.358050Z","values":{}}
{"identity":{"device_triple":"aarch64-apple-darwin","is_ci":false,"cli_version":"0.7.0-alpha.3 (ba856ac)","session_id":218853676744316928865703503826531902998},"name":"build_stage","module":null,"message":"Build stage update","stage":"starting","time":"2025-07-24T14:34:08.950001Z","values":{}}
{"identity":{"device_triple":"aarch64-apple-darwin","is_ci":false,"cli_version":"0.7.0-alpha.3 (ba856ac)","session_id":218853676744316928865703503826531902998},"name":"build_stage","module":null,"message":"Build stage update","stage":"compiling","time":"2025-07-24T14:34:09.543745Z","values":{}}
{"identity":{"device_triple":"aarch64-apple-darwin","is_ci":false,"cli_version":"0.7.0-alpha.3 (ba856ac)","session_id":218853676744316928865703503826531902998},"name":"build_stage","module":null,"message":"Build stage update","stage":"extracting_assets","time":"2025-07-24T14:34:10.142290Z","values":{}}
{"identity":{"device_triple":"aarch64-apple-darwin","is_ci":false,"cli_version":"0.7.0-alpha.3 (ba856ac)","session_id":218853676744316928865703503826531902998},"name":"build_stage","module":null,"message":"Build stage update","stage":"bundling","time":"2025-07-24T14:34:10.319760Z","values":{}}
{"identity":{"device_triple":"aarch64-apple-darwin","is_ci":false,"cli_version":"0.7.0-alpha.3 (950b12e)","session_id":207130784956002540532192240548422216472},"name":"cli_command","module":null,"message":"serve","stage":"start","time":"2025-07-24T14:55:31.419714Z","values":{"args":{"address":{"addr":null,"port":null},"always_on_top":null,"cross_origin_policy":false,"exit_on_error":false,"force_sequential":false,"hot_patch":false,"hot_reload":null,"interactive":null,"open":null,"platform_args":{"client":null,"server":null,"shared":{"args":false,"targets":{"build_arguments":{"all_features":false,"base_path":false,"bin":null,"bundle":null,"cargo_args":false,"debug_symbols":true,"device":false,"example":false,"features":false,"inject_loading_scripts":true,"no_default_features":false,"package":null,"platform":null,"profile":false,"release":false,"renderer":{"renderer":null},"rustc_args":false,"skip_assets":false,"target":null,"target_alias":"Unknown","wasm_split":false},"fullstack":null,"ssg":false}}},"watch":null,"wsl_file_poll_interval":null}}}

The full logs are available here: http://gist.github.com/ealmloff/815d859bb8c592a72769e958e685f7f2

You can opt-out of telemetry by compiling the CLI with the disable-telemetry feature, setting TELEMETRY=false in your environment variables or running dx config set disable-telemetry true

Expanded Documentation

We reorganized and expanded the documentation for core concepts in 0.7. The docs now go into more details about important concepts like reactivity, the rendering model of dioxus, and async state in dioxus. The new docs also come with a new look for the docsite with a wider panel that fits more documentation in the screen:

Screenshot_2025-08-06_at_3 40 14_PM

The new docsite also includes search results for rust items from docs.rs for more specific apis:

Screenshot_2025-08-07_at_9 17 17_AM

What's Changed

New Contributors

Full Changelog: v0.6.3...v0.7.0