GUI Basics
8 examples to get you started with desktop GUI development in Rust - 6 basic and 2 intermediate.
Search across all documentation pages
8 examples to get you started with desktop GUI development in Rust - 6 basic and 2 intermediate.
# Tauri path
npm create tauri-app@latest
# egui path
cargo add eframe egui
# iced path
cargo add icedTooling: Backend examples target Rust 1.97.0 (edition 2024). Tauri also needs Node for the frontend toolchain.
Immediate-mode UI in one eframe app.
fn main() -> eframe::Result<()> {
eframe::run_native(
"Hello egui",
eframe::NativeOptions::default(),
Box::new(|_cc| Ok(Box::new(MyApp::default()))),
)
}
#[derive(Default)]
struct MyApp {}
impl eframe::App for MyApp {
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
egui::CentralPanel::default().show(ctx, |ui| {
ui.label("Hello from Rust GUI");
});
}
}update runs every frame - keep work cheap or profile CPU.winit under eframe.Related: egui
Elm-style Message enum drives updates.
use iced::widget::{button, column, text, Column};
use iced::Element;
#[derive(Debug, Clone)]
enum Message {
Increment,
}
fn view(count: &i32) -> Element<Message> {
column![
text(format!("Count: {count}")),
button("+").on_press(Message::Increment),
]
.into()
}view function maps state to widgets.update applies messages immutably - testable reducer pattern.Related: iced
Rust command callable from JavaScript UI.
#[tauri::command]
fn greet(name: &str) -> String {
format!("Hello, {name}!")
}Related: Tauri
Arc<Mutex<_>> in TauriMultiple commands mutating shared app state.
use std::sync::Mutex;
use tauri::State;
struct AppState {
counter: Mutex<i32>,
}
#[tauri::command]
fn increment(state: State<AppState>) -> i32 {
let mut c = state.counter.lock().unwrap();
*c += 1;
*c
}State<T> manages lifetime across invocations.tokio::sync::Mutex in async commands to avoid blocking async runtime.Related: State & Architecture
Delegate filesystem picking to OS APIs via plugin or rfd crate.
fn pick_file() -> Option<std::path::PathBuf> {
rfd::FileDialog::new().pick_file()
}tauri.conf.json.Related: Native Integration
Desktop apps need quit, preferences, and background behavior.
tauri::menu and tray APIs in Rust setup hook.Related: Native Integration
Load config on startup, save on change with serde JSON.
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Default)]
struct Settings {
dark_mode: bool,
}Related: State & Architecture
Ship .app, .msi, or .deb with icons and metadata.
cargo tauri build
# or cargo install cargo-bundle && cargo bundleRelated: Packaging & Distribution
Stack versions: This page was written for Rust 1.97.0 (edition 2024), Tokio 1.x, Axum 0.8, serde 1.0, sqlx 0.8, clap 4, and Polars 0.46+.
Reviewed by Chris St. John·Last updated Jul 16, 2026