Introducing bwu_redux: Redux-Style State Management for Rust, Now Open Source
2026-07-17
Filed under: Announcements
In our last post we made the case for pairing Redux-style state management with Rust. Today that's no longer just an argument — it's a crate you can add to your project. bwu_redux is now open source, published on crates.io and GitHub under a dual MIT/Apache-2.0 license.
It's the same state management library behind BWU Designer's frontend, extracted so anyone can use it independently of our app.
What it does
bwu_redux is an async, Redux-style store for Rust: a single immutable state, actions dispatched through a middleware chain, and a pure reducer that produces the next state. State changes are broadcast to subscribers as async streams, driven by selectors that extract just the slice of state a subscriber actually cares about — so a subscriber is only woken up when the value it selected actually changes, not on every dispatch.
A few things worth calling out specifically:
- Undo for free. With the
historyfeature enabled (on by default), the store keeps the last N states automatically. Undo isn't a separate system bolted on top — it falls out of the same append-only state log that makes the store predictable in the first place. - Time-travel debugging. The
redux_devtoolsfeature streams every state change to a DevTools gRPC server for live inspection, using the same wire format whether your app is running natively or in the browser. - One codebase, two runtimes. The exact same store, actions, and reducer logic run
unmodified on native targets and in WASM via
wasm-bindgen/gloo— including the DevTools connection, which just switches to gRPC-web in the browser.
Getting started
use std::sync::Arc;
use bwu_redux::{StoreConfig, StoreWrapper};
#[tokio::main]
async fn main() {
let config = StoreConfig::new(String::from("initial"), |state: String, action: &String| {
if action.is_empty() { state } else { action.clone() }
});
let store = Arc::new(StoreWrapper::new(config));
store.run();
store.dispatch(String::from("hello")).expect("store is running");
store.close(String::new()).await.expect("close failed");
assert_eq!(store.select(|s| s.clone()), "hello");
}
State and action types just need Clone + Debug + PartialEq + Send + Sync — add
serde::Serialize/Deserialize if you want the redux_devtools feature. The
README has a more complete example with
tracing set up, and the full feature-flag reference.
Try it, and tell us what breaks
This is a 0.1.0 release: the core store, middleware, undo history, and DevTools
integration are all in daily use inside BWU Designer, but the crate is young and the
API may still shift. If you try it and hit a rough edge — or just want to see how the
DevTools protocol works — issues and pull requests are welcome on
GitHub.
[dependencies]
bwu_redux = "0.1"