- Published on
Modern Rust 2026 — Rust 1.85 / Edition 2024 / Tokio / Axum 0.8 / Loco / Leptos / Bevy / Tauri 2 / Embassy Deep-Dive Guide
- Authors

- Name
- Youngju Kim
- @fjvbn20031
- 1. Modern Rust in 2026 — what edition 2024 brought
- 2. Rust 1.85 + Edition 2024 — gen blocks, async closures, never type fallback
- 3. Tokio — the async runtime standard
- 4. Axum 0.8 — popular Tower-based web framework
- 5. Actix-Web 4 / Rocket 0.5 — performance vs DX
- 6. Loco — Rails for Rust
- 7. Leptos 0.7 — fine-grained reactivity on the front
- 8. Dioxus / Yew — React / Elm-style options
- 9. Database — sqlx / Diesel 2 / SeaORM
- 10. Bevy 0.15 — ECS game engine
- 11. Tauri 2 — desktop + mobile
- 12. ML — Burn / Candle / mistral.rs
- 13. Embassy — async embedded
- 14. Tooling — cargo-binstall / rust-analyzer / RustRover / Helix
- 15. Korea / Japan — Kakao, Toss, Mercari, ZOZO, Sansan
- 16. Who should pick Rust — systems / embedded / full-stack / games
- 17. References
1. Modern Rust in 2026 — what edition 2024 brought
Rust 1.85 shipped on February 20, 2025. That same day, edition 2024 became the default for new projects. Rust editions arrive on a three-year cadence and act as the "language design closing report" — after 2015 → 2018 → 2021, the fourth edition (2024) made the largest changes to async and lifetimes.
Five key changes:
- RPIT lifetime capture rules changed (
-> impl Trait) — all in-scope lifetimes are now captured. The+ '_hell you used to dodge with.unwrap()orboxed()is largely gone. async fnin traits is official — AFIT stabilized in 1.75, and combined with edition 2024 libraries can accept async viadyntrait more easily.genblocks /gen fn— Python-style generator syntax landed in Rust. Writing theIteratortrait by hand is much rarer.- async closures (
async ||) — the pattern of wrapping a closure body inasync move { ... }disappears. - never type fallback unified to
!— when inference was ambiguous, it used to fall back to(), but now it consistently falls back to!. Error messages are clearer and "why did the compiler pick this?" moments shrink.
Add these five together and "Rust written in edition 2021" and "Rust written in edition 2024" do not feel like the same language. The change is most visible to web/server folks — Tokio 1.x + Axum 0.8 + Tower now approaches "Express-style lightweight code."
This post surveys the entire 2026-May Rust ecosystem layered on top of that change. Web, DB, game, desktop, mobile, ML, embedded, tooling, IDE — plus where Korea and Japan are with adoption.
2. Rust 1.85 + Edition 2024 — gen blocks, async closures, never type fallback
2.1 gen blocks — no more hand-rolled Iterator
// Edition 2021: implement Iterator by hand
struct Counter { n: u32, max: u32 }
impl Iterator for Counter {
type Item = u32;
fn next(&mut self) -> Option<u32> {
if self.n < self.max { self.n += 1; Some(self.n) } else { None }
}
}
// Edition 2024 (1.85, when gen gate is passed): gen fn
gen fn counter(max: u32) -> u32 {
let mut n = 0;
while n < max {
n += 1;
yield n;
}
}
yield is now a keyword and gen fn compiles to impl Iterator<Item = u32> automatically. The async sibling (async gen / Stream integration) is following the same track.
2.2 async closures
// Edition 2021: wrap once more in async move {}
let xs = vec![1, 2, 3];
let futs = xs.into_iter().map(|x| async move { process(x).await });
// Edition 2024: async closure itself
let xs = vec![1, 2, 3];
let futs = xs.into_iter().map(async |x| process(x).await);
Code at tokio::spawn, futures::join_all, stream::then shrinks by a line each.
2.3 RPIT lifetime capture
// Edition 2021: must opt in to capturing 'a or compile fails
fn names<'a>(xs: &'a [String]) -> impl Iterator<Item = &'a str> + use<'a> {
xs.iter().map(|s| s.as_str())
}
// Edition 2024: in-scope lifetimes captured automatically
fn names<'a>(xs: &'a [String]) -> impl Iterator<Item = &'a str> {
xs.iter().map(|s| s.as_str())
}
The + use<'a> annotation disappears. The trade-off: a lifetime that was not captured before now is, and some patterns silently become unusable — a migration lint flags them.
2.4 never type fallback
In Result::Err::<i32, _>(panic!()) the _ used to be inferred as (), occasionally producing weird trait conflicts. Now it falls to !. Macro authors breathe out.
3. Tokio — the async runtime standard
In 2026 the Rust async runtime is effectively a single standard: Tokio 1.x. Competitors are async-std (development stalled), smol (embedded / single-threaded), and monoio (Cloudflare's io_uring-only runtime).
Why Tokio won:
- Ecosystem weight: hyper, reqwest, sqlx, tokio-postgres, axum, tower, tonic all run on Tokio
- Scheduler quality: the work-stealing scheduler is on par with Go's GOMAXPROCS maturity
- First-class features like
tokio::select!,JoinSet,LocalSet - io_uring support (
tokio-uring) — single-syscall network IO on Linux
// Minimal Tokio server
use tokio::net::TcpListener;
use tokio::io::{AsyncReadExt, AsyncWriteExt};
#[tokio::main]
async fn main() -> std::io::Result<()> {
let listener = TcpListener::bind("0.0.0.0:8080").await?;
loop {
let (mut socket, _) = listener.accept().await?;
tokio::spawn(async move {
let mut buf = vec![0; 1024];
loop {
let n = match socket.read(&mut buf).await {
Ok(0) => return,
Ok(n) => n,
Err(_) => return,
};
if socket.write_all(&buf[..n]).await.is_err() { return; }
}
});
}
}
#[tokio::main] builds a multi-threaded work-stealing runtime; tokio::spawn throws tasks onto it. If you want a single thread, switch to the current_thread runtime — that choice becomes important on embedded and WASM.
4. Axum 0.8 — popular Tower-based web framework
Axum is built by the Tokio team. With 0.8 (November 2024) the biggest change was that path syntax moved from the :id style to the {id} style.
use axum::{Router, routing::get, extract::Path};
#[tokio::main]
async fn main() {
let app = Router::new()
.route("/", get(|| async { "hello" }))
.route("/users/{id}", get(get_user))
.route("/health", get(|| async { "ok" }));
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
axum::serve(listener, app).await.unwrap();
}
async fn get_user(Path(id): Path<u64>) -> String {
format!("user {}", id)
}
Why Axum is loved:
- Tower middleware compatible — drop in
CompressionLayer,TraceLayer,CorsLayerfromtower-httpdirectly - Extractors in the function signature —
Path,Query,Json,Stateas parameters get auto-parsed - Routing enforced by types — wrong handler signature is a compile error
- First-class WebSocket / SSE
use axum::{Json, extract::State};
use serde::{Deserialize, Serialize};
#[derive(Deserialize)] struct CreateUser { name: String }
#[derive(Serialize)] struct User { id: u64, name: String }
async fn create_user(
State(db): State<DbPool>,
Json(body): Json<CreateUser>,
) -> Json<User> {
let id = sqlx::query_scalar!("INSERT INTO users(name) VALUES($1) RETURNING id", body.name)
.fetch_one(&db).await.unwrap();
Json(User { id: id as u64, name: body.name })
}
This pattern is effectively the 2026 standard for Rust backends. Loco sits on top of it.
5. Actix-Web 4 / Rocket 0.5 — performance vs DX
5.1 Actix-Web 4 — king of the benchmarks
In the TechEmpower benchmark Actix-Web stays at the top in nearly every round. It has its own actor system (actix), but 4.x raised Tokio compatibility so plain async/await works fine.
use actix_web::{get, web, App, HttpServer, Responder};
#[get("/users/{id}")]
async fn get_user(path: web::Path<u64>) -> impl Responder {
format!("user {}", path.into_inner())
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(|| App::new().service(get_user))
.bind("0.0.0.0:3000")?
.run()
.await
}
If you need to squeeze out the last millisecond, check Actix. The downside is that the error-handling and middleware APIs are not as crisp as Axum/Tower.
5.2 Rocket 0.5 — async at last
Rocket is famous for its macro-magic style, but async came late (0.5 stable only in November 2023). In 2026 it remains attractive for learning, internal tools, and hobby projects, but new production-weight projects tend to flow to Axum/Loco.
#[macro_use] extern crate rocket;
#[get("/users/<id>")]
async fn get_user(id: u64) -> String { format!("user {}", id) }
#[launch]
fn rocket() -> _ {
rocket::build().mount("/", routes![get_user])
}
Intuitive — but Axum writes the same feature more honestly.
6. Loco — Rails for Rust
Loco first appeared in August 2023, calling itself "Rails for Rust." It bundles components like Axum + sea-orm + tower + sidekiq-rs to produce a "CRUD running from a single scaffold command" experience.
cargo install loco-cli
loco new my_app
cd my_app
cargo loco start
# Rails-style generators
cargo loco generate scaffold post title:string body:text
cargo loco db migrate
cargo loco start
Two lines and you get a /posts CRUD router, sea-orm model, migration, validator, and view. Background workers use Sidekiq, email uses lettre, auth is JWT — the bundle is decided for you, lowering decision cost.
Where Loco fits:
- People who love Rails / Phoenix / Laravel and want to move to Rust
- Teams with high "what do I pick in Rust?" decision fatigue
- Downside: because the bundle is fixed, stepping outside it is heavier than writing plain Axum
In May 2026 Loco is stabilizing around 0.13, and Korean / Japanese startups increasingly call it "the least painful Rust full-stack for side projects."
7. Leptos 0.7 — fine-grained reactivity on the front
Leptos is a Rust frontend framework with a fine-grained reactivity model inspired by SolidJS. In 0.7 (late 2024 to stable in 2025) the reactive system was rewritten and SSR / hydration / islands became smoother.
use leptos::prelude::*;
#[component]
fn Counter() -> impl IntoView {
let (count, set_count) = signal(0);
view! {
<button on:click=move |_| set_count.update(|n| *n += 1)>
"Count: " {count}
</button>
}
}
fn main() { leptos::mount::mount_to_body(Counter); }
What Leptos brings:
- No VDOM — signals update DOM nodes directly. Faster than React, smaller memory
view!macro gives a JSX-like syntax- SSR + hydration all in one Rust language (no Next.js-style split)
cargo-leptosbundles build, HMR, and SSR server- server functions —
#[server]macro lets a function run on the server and be called from the client
#[server(GetTodos)]
async fn get_todos() -> Result<Vec<Todo>, ServerFnError> {
let pool = use_context::<DbPool>().expect("pool");
sqlx::query_as!(Todo, "SELECT * FROM todos").fetch_all(&pool).await
.map_err(|e| ServerFnError::new(e.to_string()))
}
This function becomes an RPC the client can call directly — type-safe, no boilerplate. Same concept as Remix loaders, Next server actions, and SolidStart actions.
8. Dioxus / Yew — React / Elm-style options
8.1 Dioxus — React-like
Dioxus is the Rust frontend closest to React. It has a VDOM, has hooks, and components are functions. 0.6 in 2024 and 0.7 in 2025 made desktop, mobile, web, and server build from one tree.
use dioxus::prelude::*;
fn App() -> Element {
let mut count = use_signal(|| 0);
rsx! {
button { onclick: move |_| count += 1, "Count: {count}" }
}
}
fn main() { dioxus::launch(App); }
A single dioxus serve ships desktop, web, iOS, and Android from the same code — a renderer track of its own, different from Tauri / Capacitor.
8.2 Yew — Elm/React-like, the oldest choice
Yew is the oldest (2017) Rust frontend project. It started Elm-ish with a message pattern and now resembles React hooks. Leptos / Dioxus look newer, but Yew has stability and docs in its favor.
use yew::prelude::*;
#[function_component]
fn Counter() -> Html {
let count = use_state(|| 0);
let onclick = {
let count = count.clone();
Callback::from(move |_| count.set(*count + 1))
};
html! { <button {onclick}>{"Count: "}{*count}</button> }
}
fn main() { yew::Renderer::<Counter>::new().render(); }
Picking (May 2026):
- Fine-grained reactivity + SSR is core → Leptos
- React-style mental model + full-stack mobile/desktop in one code → Dioxus
- Proven libraries, docs, tutorials → Yew
9. Database — sqlx / Diesel 2 / SeaORM
9.1 sqlx — async, raw SQL, compile-time checks
sqlx lets you write raw SQL but validates queries against the DB at compile time. The macros are the magic.
use sqlx::PgPool;
#[derive(sqlx::FromRow)]
struct User { id: i64, name: String }
async fn get_user(pool: &PgPool, id: i64) -> Result<User, sqlx::Error> {
sqlx::query_as!(User, "SELECT id, name FROM users WHERE id = $1", id)
.fetch_one(pool).await
}
The query_as! macro connects to PostgreSQL at compile time and validates the types of the id and name columns. CI catches SQL typos. Downside: the build environment needs a DB (offline mode via sqlx prepare).
9.2 Diesel 2 — the sync ORM standard
Diesel is sync API + a strong type-based query builder. Ergonomics improved a lot in 2.0 (2022). If async is not required (CLIs, single-threaded workers, migration tools), Diesel is still strong.
use diesel::prelude::*;
#[derive(Queryable)]
struct User { id: i64, name: String }
let users: Vec<User> = users::table
.filter(users::name.like("alice%"))
.load(&mut conn)?;
9.3 SeaORM — async ORM, ActiveRecord style
SeaORM generates entities from the DB with sea-orm-cli and exposes an ActiveRecord-ish API like Entity::find().filter(...).all(&db).await. Loco's adoption of SeaORM gave it a tailwind.
use sea_orm::{EntityTrait, QueryFilter, ColumnTrait};
let users = users::Entity::find()
.filter(users::Column::Name.contains("alice"))
.all(&db).await?;
Picking:
- Raw SQL is comfortable and compile-time checks matter → sqlx
- Type-based query builder + sync OK → Diesel 2
- ORM style + async + many DB drivers → SeaORM
10. Bevy 0.15 — ECS game engine
Bevy is the headline Rust game engine, and ECS (Entity-Component-System) is the core architecture. 0.15 (November 2024) brought required components, an animation system rewrite, picking, and standardized error handling.
use bevy::prelude::*;
#[derive(Component)] struct Player;
#[derive(Component)] struct Velocity(Vec3);
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_systems(Startup, spawn_player)
.add_systems(Update, move_player)
.run();
}
fn spawn_player(mut commands: Commands) {
commands.spawn((Player, Velocity(Vec3::ZERO), Transform::default()));
}
fn move_player(time: Res<Time>, mut q: Query<(&mut Transform, &Velocity), With<Player>>) {
for (mut t, v) in &mut q {
t.translation += v.0 * time.delta_secs();
}
}
The essence of ECS is "separate data (Component) from behavior (System), and each system queries only the component combinations it cares about." The multiple-inheritance and giant base classes familiar from OOP game code disappear.
Bevy in 2026:
- Indie games and game jams adopt it quickly
- Large studios cannot leave Unity / Unreal, but "as Unity's pricing shakes confidence, people are leaking toward Rust" — a signal you can see
- Weaknesses: still the editor (official editor is alpha) and the mobile build pipeline
11. Tauri 2 — desktop + mobile
Tauri is an Electron alternative. It hosts a webview natively (WKWebView on macOS, WebView2 on Windows, WebKitGTK on Linux) and writes backend logic in Rust. The biggest change in Tauri 2 (October 2024) is mobile support (iOS / Android).
cargo install create-tauri-app
cargo create-tauri-app
cd my-app
cargo tauri dev
# iOS / Android builds
cargo tauri ios dev
cargo tauri android dev
Tauri vs Electron:
| Item | Tauri 2 | Electron |
|---|---|---|
| Backend language | Rust | Node.js |
| webview | OS native | bundled Chromium |
| Binary size | ~3-10 MB | ~80-150 MB |
| Memory | ~50-100 MB | ~150-400 MB |
| Mobile | iOS/Android | No |
Electron's killer strength is "Chromium is the same everywhere." Debugging the subtle gaps between Safari WebKit and WebView2 is Tauri's cost. Even so, the memory / binary difference is large, and the safety guarantees a Rust backend brings around syscalls are attractive.
// src-tauri/src/lib.rs
#[tauri::command]
fn greet(name: &str) -> String { format!("Hello, {}!", name) }
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
tauri::Builder::default()
.invoke_handler(tauri::generate_handler![greet])
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
From the frontend, await invoke('greet', { name: 'Alice' }) runs the Rust function and returns the result. RPC code generation, the capability system, and the plugin ecosystem all got more polished in v2.
12. ML — Burn / Candle / mistral.rs
The Rust ML ecosystem grew fast in 2024-2025. Three pieces matter:
12.1 Candle — HuggingFace's minimalist ML
Candle is HF's "lighter than PyTorch, friendlier than ONNX" Rust ML library. It compiles to WASM directly and lets you pick Metal / CUDA / CPU backends.
use candle_core::{Device, Tensor};
let device = Device::Cpu;
let a = Tensor::randn(0f32, 1.0, (2, 3), &device)?;
let b = Tensor::randn(0f32, 1.0, (3, 4), &device)?;
let c = a.matmul(&b)?;
println!("{:?}", c.shape());
Models like LLaMA, Mistral, Whisper, and Stable Diffusion are already ported in candle-transformers. For inference-only on desktop / edge, Candle is the lightest.
12.2 Burn — training too
Burn is the full-stack ML framework for people who want both training and inference in Rust. PyTorch-like API, backend abstraction (WGPU, CUDA, NdArray, LibTorch), and autodiff.
use burn::tensor::{Tensor, backend::Backend};
fn linear<B: Backend>(x: Tensor<B, 2>) -> Tensor<B, 2> {
let w = Tensor::random([784, 10], Distribution::Default, &x.device());
x.matmul(w)
}
12.3 mistral.rs — LLM inference optimized
mistral.rs is one of the libraries that pushed LLM inference in Rust hardest. PagedAttention, quantization (GGUF, GPTQ, AWQ), grammar-constrained output, and an OpenAI-compatible server — all in a single binary.
mistralrs-server --port 1234 plain -m mistralai/Mistral-7B-Instruct-v0.2
Picking guide:
- Inference only + desktop / edge → Candle
- Training in Rust too → Burn
- Quickly stand up LLM serving → mistral.rs
13. Embassy — async embedded
Embassy is the async standard for embedded Rust. No RTOS — interrupts, DMA, and timers handled with async/await. The STM32 / nRF / RP2040 / ESP32 (partial) HALs evolve together.
#![no_std]
#![no_main]
use embassy_executor::Spawner;
use embassy_time::{Duration, Timer};
use embassy_stm32::gpio::{Level, Output, Speed};
#[embassy_executor::main]
async fn main(_spawner: Spawner) {
let p = embassy_stm32::init(Default::default());
let mut led = Output::new(p.PC13, Level::High, Speed::Low);
loop {
led.toggle();
Timer::after(Duration::from_millis(500)).await;
}
}
Traditional embedded code writes interrupt handlers by hand and runs state machines like "what state am I in?" by hand. Embassy expresses those naturally in async/await — Timer::after(...).await compiles to an interrupt-based sleep.
Core crates:
embassy-executor— no_std async executorembassy-time— timers / delaysembassy-net— TCP/IP (smoltcp-based)embassy-stm32/embassy-nrf/embassy-rp— HALs
14. Tooling — cargo-binstall / rust-analyzer / RustRover / Helix
14.1 cargo-binstall — install cargo tools without compiling
cargo install ripgrep builds ripgrep from source. That is minutes of time and a hot laptop. cargo binstall ripgrep pulls the prebuilt binary from GitHub releases.
cargo install cargo-binstall
cargo binstall ripgrep fd-find sd dust tokei cargo-watch cargo-edit
Half the cargo tools already ship binstall metadata. Average install time goes from 30 seconds to 3.
14.2 cargo-watch — rerun on file change
cargo binstall cargo-watch
cargo watch -x test
cargo watch -x run
cargo watch -x 'run --bin server'
Almost everyone keeps it open while developing Tauri / Leptos / Axum.
14.3 cargo-leptos — Leptos-specific dev server
cargo leptos serve bundles the SSR server + WASM client + asset handling. HMR works — a Next.js-dev-server-like experience.
14.4 cargo-mobile2 — Rust mobile builds
Wrapper to build Dioxus / Tauri / general Rust libraries against iOS / Android targets. v1 was partially abandoned and the mobile2 fork became the de facto standard.
14.5 rust-analyzer — LSP
rust-analyzer is the de facto Rust LSP. It is the first dependency in VS Code / Helix / Neovim / Zed. Macro expansion speed, async trait inference, and lifetime hints all got better in 2025.
14.6 RustRover — JetBrains official
JetBrains turned IntelliJ-Rust into RustRover in 2023, an official product. Free for non-commercial use since September 2024. Strong debugger integration, profiler, and refactoring.
14.7 Helix — modal editor written in Rust
Helix is a modal editor written in Rust (neovim-style but selection-first). LSP integration, tree-sitter highlighting are default, and key bindings differ from vim (selection → action). Light and fast startup are the draws.
15. Korea / Japan — Kakao, Toss, Mercari, ZOZO, Sansan
15.1 Korea
- Kakao — Rust in parts of infra / search services. Kakao Enterprise gives Rust talks occasionally
- Toss — Rust adoption examples in some of Tossbank's payment infra (gRPC servers / latency-critical paths)
- Naver — Rust in hyperscale AI infra; pieces of NSML
- Samsung — Tizen parts, areas of Galaxy firmware exploring Rust
Overall the pattern is "partial adoption in specific latency-critical services / specific infra components" rather than company-wide.
15.2 Japan
Japan is one beat ahead of Korea in Rust adoption.
- Mercari — Rust migration in parts of search / recommendation. Many tech blog posts
- ZOZO — Rust in some ZOZOTOWN microservices, with WebAssembly examples
- Sansan — Rust in hot paths of business-card OCR / data pipelines
- CyberAgent — Rust in ad bidding systems / parts of game backends
- DeNA — Game / mobility backends in part
- LINE (LY) — Messaging / media processing in part
Mercari especially has published Rust case studies steadily since 2022-2023, and Rust job postings for senior backend engineers in Japan have grown noticeably.
16. Who should pick Rust — systems / embedded / full-stack / games
Rust is not a cure-all. There are great fits, and there are "why bother?" fits.
16.1 Where Rust shines
- Systems programming — kernel modules, drivers, OSes, virtualization. The Linux kernel formally accepts Rust now
- Embedded — async embedded without an RTOS, via Embassy + no_std
- High-performance network services — when P99 latency matters in milliseconds (messaging, payments, ad bidding)
- WebAssembly — wasm-pack / wasm-bindgen / trunk. Heavy compute in the browser
- CLI tools — ripgrep / fd / bat / dust / zoxide. Easy distribution and fast
- Blockchain / crypto — Polkadot, Solana, foundry, reth
- Games (especially indie) — Bevy ECS + memory safety
16.2 Where Rust is overhead
- CRUD-heavy internal systems — Python / Go usually finish faster (developer time)
- Prototype fast + throw away often — borrow checker slows prototyping
- Data analytics / ML training itself — Python's ecosystem dominates
- Trivial scripts — Bash / Python / Deno are enough
- Teams with many juniors — Rust's learning curve is steep
16.3 A 2026 Rust learning roadmap
- The Rust Book (rust-lang.org/book) — required first book. Reflects edition 2024
- Rust by Example — code-led
- Rustlings — 100+ small exercises
- Async Book — the async/await model
- Tokio Tutorial — how Tokio works
- Axum 0.8 docs + build a small CRUD
- (By interest) a toy in Bevy / Tauri / Leptos / Embassy
Reach that and you are at the "I can really make something in Rust" stage. Average 3-6 months. To move faster, start your first toy project as early as possible — reading alone will not beat the borrow checker.