Rust GUI Full-Stack
Quick Start (Decision Tree)
- •Pick a UI approach
- •Need native widgets + production desktop app quickly → prefer Slint (retained-mode, UI markup + Rust logic).
- •Need lightweight immediate-mode tooling UI/debug panels → prefer egui.
- •Need a Rust-native, fairly “app-like” GUI with widget tree → prefer Iced.
- •Need a game/3D/visualization engine + ECS → prefer Bevy.
- •Pick a rendering approach
- •Default: use the GUI’s renderer or wgpu integration.
- •Need custom GPU pipelines, shaders, offscreen textures, or high-performance charts → use wgpu directly and embed the surface/texture into your GUI framework.
- •Pick a backend/runtime shape
- •UI + async I/O, no HTTP server → single process with Tokio; UI thread + async tasks via channels.
- •UI + local API server (plugin/automation) → Axum or Actix Web on Tokio; keep UI responsive with message passing.
If you’re unsure: start with Tokio + channels, keep UI state single-threaded, and treat async tasks as producers of messages/events.
Workflow: Build a Responsive Rust Desktop App
- •Define state + messages (UI-driven architecture)
- •Keep a small, well-typed
AppStateowned by the UI thread. - •Model external effects as commands/tasks that emit
Msgback to the UI.
- •Isolate concurrency
- •Prefer message passing over shared mutable state.
- •If sharing is required: use
Arc<Mutex<T>>/Arc<RwLock<T>>and keep lock scopes tiny. - •Never block the UI thread on I/O; do I/O in async tasks or worker threads.
- •Integrate rendering safely
- •Treat GPU objects (device/queue/pipelines) as owned resources; avoid cloning heavy handles unless the API intends it.
- •If the framework requires
'staticclosures, move only lightweight handles (Arc, IDs) and keep actual state inAppState.
- •Structure the repo
- •
crates/app(GUI) owns state, routing, and view composition. - •
crates/coreowns domain types, validation, pure logic (no UI dependencies). - •
crates/ioowns I/O clients, persistence, network protocols (async). - •Optional
crates/renderowns wgpu pipelines/shaders.
Patterns to Prioritize
Zero-cost & idiomatic Rust
- •Prefer iterators and borrowing over cloning.
- •Prefer
&str/Cow<'a, str>for text; avoid allocating in hot paths. - •Use
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]where it helps ergonomics without hidden costs.
Thread safety by design
- •Use
Send + Syncboundaries explicitly: background tasks produceMsgvalues; UI consumes. - •Prefer
tokio::sync::mpsc/oneshotfor command responses; avoid ad-hoc globals.
UI performance
- •Minimize per-frame allocations; cache layout and precompute expensive data.
- •For immediate-mode GUIs: keep derived rendering data cached and invalidated on change.
What to Load Next (References)
- •Need to choose a GUI framework or understand their strengths/tradeoffs → read
references/gui-frameworks.md. - •Need wgpu architecture, swapchain/surface rules, and shader/pipeline patterns → read
references/graphics-wgpu.md. - •Need Tokio + Axum/Actix integration patterns and clean layering → read
references/backend-async.md. - •Need Rust ownership/concurrency “recipes” for GUIs (lifetimes,
Arc,Mutex, channels) → readreferences/memory-concurrency.md.