- Published on
Rust エコシステム 2026 完全ガイド — Rust 1.85+ / tokio / axum / actix-web / sqlx / Bevy / Tauri / Leptos / Dioxus / Embassy / Cargo 徹底解説
- Authors

- Name
- Youngju Kim
- @fjvbn20031
はじめに — 2026年5月、Rust は「システム言語の標準」になった
2024年末に rust-for-linux のパッチがメインラインへマージされた瞬間、Rust は「期待の言語」から「Linux が採用した言語」へと立場を変えた。2026年5月の現在、その流れはさらに鮮明だ。Cloudflare の Pingora(NGINX を社内で置き換える Rust 製プロキシ)は1日に40兆件を超えるリクエストをさばき、Discord の Read Statesサービスは Rust への書き換えで GC ポーズを排除し 99.99% の安定性を達成、Dropbox の Magic Pocket ストレージエンジン、Figma のマルチプレイヤー HTTP レイヤー、Mozilla の Servo(2024年に Linux Foundation へ移管)も Rust で動いている。
本稿はマーケティング比較ではない。「2026年5月時点で本番運用される Rust スタックは具体的にどう組まれているか」を 1.85 / 2024 エディションの変更点から、tokio のスケジューラ、axum / sqlx の実コード、Tauri 2 のモバイル GA、Bevy 0.15 の ECS、Embassy の no_std async、そして韓国・日本での採用事例まで通しで解説する。
Rust 2026 スタック — 8レイヤーへの分解
まず全体像から。2026年の標準的な Rust スタックは次の 8 レイヤーに分かれる。
- 言語/ツールチェーン:rustc、cargo、rustup、rust-analyzer
- async ランタイム:tokio が事実上の標準。async-std / smol / embassy はニッチ
- Web/ネットワーク:axum、actix-web 5、poem、rocket 0.5、warp、salvo、loco-rs
- データ/ORM:sqlx、sea-orm、diesel 2.x、rbatis
- エラー/オブザーバビリティ:anyhow、thiserror、eyre、snafu、miette、tracing
- GUI/レンダリング:Tauri 2、egui、Iced、Slint、Dioxus、Yew、Leptos、Sycamore
- システム/組込/ゲーム:Embassy、RTIC、embedded-hal、Bevy、winit、gtk-rs
- ツール群:cargo-nextest、cargo-mutants、cargo-deny、cargo-audit、cross、binstall
ひとつのクレートが各レイヤーを独占した時代は終わった。バックエンドの事実上の標準は「axum + tokio + sqlx + tracing」で、GUI は「Tauri 2 + Leptos / Dioxus」か「egui / Slint」へ分岐する。以下、レイヤーごとに見ていく。
Rust 1.85 と 2024 エディション — async fn in trait、let-else、GAT の安定化
Rust 1.85 は 2024 エディションの最初の安定リリースだ。主な変更点は次の通り。
- async fn in trait(RPITIT):もはや
async-traitマクロは必須ではない。dyn-safe 制約は残るが、静的ディスパッチならマクロなしで書ける。 - GAT(Generic Associated Types):1.65 で安定化済み。2024 エディションで多くの lint が整理された。
- let-else:1.65 以降利用可能。2024 エディションで
if letの一時値ライフタイムが直感的になった。 - never type フォールバック:
!のフォールバックが()から!に変わり、より厳格に。明示的な型注釈が必要なコードが出る。 - raw lifetime /
r#:識別子衝突を解消。
代表的な 1.85 スタイルのトレイト定義は次のとおり。
use std::error::Error;
// 2024 エディション:async fn in trait、マクロ不要
pub trait UserRepo {
async fn find_by_id(&self, id: u64) -> Result<Option<User>, Box<dyn Error + Send + Sync>>;
async fn create(&self, user: NewUser) -> Result<User, Box<dyn Error + Send + Sync>>;
}
pub struct User { pub id: u64, pub email: String }
pub struct NewUser { pub email: String }
pub struct PgUserRepo { pool: sqlx::PgPool }
impl UserRepo for PgUserRepo {
async fn find_by_id(&self, id: u64) -> Result<Option<User>, Box<dyn Error + Send + Sync>> {
let row = sqlx::query_as::<_, (i64, String)>("SELECT id, email FROM users WHERE id = $1")
.bind(id as i64)
.fetch_optional(&self.pool)
.await?;
Ok(row.map(|(id, email)| User { id: id as u64, email }))
}
async fn create(&self, user: NewUser) -> Result<User, Box<dyn Error + Send + Sync>> {
let row: (i64,) = sqlx::query_as("INSERT INTO users(email) VALUES ($1) RETURNING id")
.bind(&user.email)
.fetch_one(&self.pool)
.await?;
Ok(User { id: row.0 as u64, email: user.email })
}
}
tokio ランタイム内部 — ワークスティーリング、LIFO スロット、協調的スケジューリング
tokio は M:N のワークスティーリング型スケジューラを使う。中核となる仕組みは三つ。
- ローカルキュー + グローバルキュー:各ワーカーはローカルキュー(LIFO スロット 1 個 + FIFO 256 個)を持ち、溢れたら半分をグローバルキューへ移す。
- LIFO スロット:直近に
wake()されたタスクを優先的にポーリングし、キャッシュ局所性を保つ。 - ワークスティーリング:自分のキューが空になったら、ランダムに別のワーカーのキューを半分奪う。
tokio 1.40 以降、協調的スケジューリング(cooperative scheduling)のデフォルト予算は 128。1 つのタスクが 128 回ポーリングされると自動的に譲歩(yield)する。タイトループで tokio::task::yield_now().await を書く必要は事実上なくなった。
use tokio::sync::mpsc;
use tokio::time::{sleep, Duration};
#[tokio::main(flavor = "multi_thread", worker_threads = 8)]
async fn main() {
let (tx, mut rx) = mpsc::channel::<u64>(1024);
// プロデューサー 100 個
for i in 0..100u64 {
let tx = tx.clone();
tokio::spawn(async move {
for j in 0..1000u64 {
let _ = tx.send(i * 1_000 + j).await;
if j % 100 == 0 { sleep(Duration::from_micros(10)).await; }
}
});
}
drop(tx);
// 単一コンシューマー
let mut count = 0u64;
while let Some(_v) = rx.recv().await { count += 1; }
println!("received: {count}");
}
#[tokio::main] は糖衣であり、内部的には tokio::runtime::Builder::new_multi_thread() を呼ぶ。ライブラリではマクロではなくビルダーを直接使うのが一般的だ。
async ランタイム比較 — tokio vs async-std vs smol vs embassy
| ランタイム | 主用途 | スレッディング | I/O バックエンド | 備考 |
|---|---|---|---|---|
| tokio | サーバー/ネットワーク標準 | multi-thread / current-thread | mio(epoll / kqueue / IOCP) | 2026 年の事実上の標準 |
| async-std | シンプル API 指向 | multi-thread | smol ベース | メンテモード、新規採用は非推奨 |
| smol | 軽量(約 1k LOC) | single / multi | polling / async-io | 組込/学習用途 |
| embassy | no_std / ファームウェア | 協調的、no-alloc 可 | HAL 統合 | RP2040 / STM32 / ESP32 |
| glommio | Linux 限定 io_uring | thread-per-core | io_uring | DB/ストレージ |
2026 年 5 月時点の標準パターンは「ライブラリはランタイム非依存(runtime-agnostic)に、アプリケーションは tokio を選ぶ」。#[tokio::main] をライブラリクレートに埋め込むのはマナー違反だ。
axum — 事実上の標準となった async Web フレームワーク
tokio チームが自ら開発する axum は 0.7〜0.8 を経て事実上の標準になった。特徴は tower::Service ベースのミドルウェア、強力なエクストラクタシステム、hyper の上に薄く乗ったデザインだ。
use axum::{
Router,
extract::{Path, State},
response::Json,
routing::{get, post},
http::StatusCode,
};
use serde::{Deserialize, Serialize};
use std::sync::Arc;
use sqlx::PgPool;
#[derive(Clone)]
struct AppState { pool: PgPool }
#[derive(Serialize)]
struct User { id: i64, email: String }
#[derive(Deserialize)]
struct CreateUser { email: String }
async fn get_user(
State(state): State<Arc<AppState>>,
Path(id): Path<i64>,
) -> Result<Json<User>, StatusCode> {
let row = sqlx::query_as::<_, (i64, String)>(
"SELECT id, email FROM users WHERE id = $1"
)
.bind(id)
.fetch_optional(&state.pool)
.await
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?
.ok_or(StatusCode::NOT_FOUND)?;
Ok(Json(User { id: row.0, email: row.1 }))
}
async fn create_user(
State(state): State<Arc<AppState>>,
Json(payload): Json<CreateUser>,
) -> Result<(StatusCode, Json<User>), StatusCode> {
let row: (i64,) = sqlx::query_as("INSERT INTO users(email) VALUES ($1) RETURNING id")
.bind(&payload.email)
.fetch_one(&state.pool)
.await
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
Ok((StatusCode::CREATED, Json(User { id: row.0, email: payload.email })))
}
#[tokio::main]
async fn main() {
let pool = PgPool::connect(&std::env::var("DATABASE_URL").unwrap()).await.unwrap();
let state = Arc::new(AppState { pool });
let app = Router::new()
.route("/users/:id", get(get_user))
.route("/users", post(create_user))
.with_state(state);
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
axum::serve(listener, app).await.unwrap();
}
Path, State, Json, Query のようなエクストラクタは FromRequestParts または FromRequest トレイトで拡張可能。ミドルウェアは tower::Layer で合成し Router::layer() で組み込む。
actix-web 5 と他の Web フレームワーク — poem / rocket / warp / salvo / loco-rs
axum が標準とはいえ、他のフレームワークも生きている。
- actix-web 5:アクターモデルの色は薄れ、普通の async-fn ハンドラ中心に整った。TechEmpower ベンチではいまだトップクラス。スループットを限界まで絞り出すチームに好まれる。
- poem:tokio の上に axum と似たエクストラクタ設計。
poem-openapiによる自動 OpenAPI 生成が強み。 - rocket 0.5:1.0 系で安定化したが async 対応が遅れ新規採用は減少。
- warp:フィルタコンビネータ設計。メンテ活動は縮小。
- salvo:中国コミュニティで活発。ツリーベースのルータ。
- loco-rs:「Rust の Rails」を標榜。axum + sea-orm + バックグラウンドジョブ + メーラーをフルスタックで束ねる。
| フレームワーク | 主な特徴 | 推奨シナリオ |
|---|---|---|
| axum | tower エコシステム、エクストラクタ | バックエンド標準 |
| actix-web 5 | 最上位のスループット | 超高性能ゲートウェイ |
| poem | OpenAPI が一級市民 | スキーマ駆動 API |
| loco-rs | フルスタック規約 | 「Rust の Rails」高速スタート |
| salvo | ツリールータ | 中国市場/大規模ルーティング |
sqlx / sea-orm / diesel 2.x — データベース層の比較
DB 層は三つに整理された。
- sqlx 0.8+:async、コンパイル時クエリ検査(
query!マクロ)、Postgres / MySQL / SQLite / MSSQL に対応。マイグレーションはsqlx-cli。2026 年のデフォルト。 - sea-orm:フル ORM、ActiveRecord パターン、マイグレーション DSL、
sea-orm-cliによるエンティティ生成。loco-rs のデフォルト ORM。 - diesel 2.x:同期 ORM。
diesel-asyncで async アダプタ提供。コンパイル時安全性は最強だがマクロの学習コストは高い。 - rbatis:中国コミュニティ発の async ORM。Mybatis 風 XML/マクロ。
sqlx のコンパイル時クエリ検査の例。
use sqlx::PgPool;
#[derive(sqlx::FromRow)]
struct Order { id: i64, user_id: i64, total_cents: i64, status: String }
async fn list_user_orders(pool: &PgPool, user_id: i64) -> sqlx::Result<Vec<Order>> {
// マクロがコンパイル時に DB へ接続し SELECT カラム型を検査する
let orders = sqlx::query_as!(
Order,
r#"SELECT id, user_id, total_cents, status
FROM orders
WHERE user_id = $1
ORDER BY id DESC
LIMIT 100"#,
user_id
)
.fetch_all(pool)
.await?;
Ok(orders)
}
sqlx::query_as! は DATABASE_URL か sqlx-data.json(オフラインモード)でスキーマを参照する。CI ではオフラインモードを使うのが標準だ。
| クレート | スタイル | 安全性 | async | 推奨用途 |
|---|---|---|---|---|
| sqlx | SQL 優先 + マクロ検査 | コンパイル時 | ネイティブ | バックエンド標準 |
| sea-orm | ActiveRecord ORM | ランタイム | ネイティブ | フルスタック/loco-rs |
| diesel | 型付き DSL | コンパイル時最強 | アダプタ要 | 安全性最優先 |
| rbatis | XML / マクロ SQL | ランタイム | ネイティブ | 中国市場互換 |
エラー処理 — anyhow / thiserror / eyre / snafu / miette
エラー処理クレートは二軸に分かれる。
- ライブラリ用エラー型の定義:
thiserror(derive マクロ)、snafu(コンテキスト付与を重視)。 - アプリケーション用エラー集約:
anyhow(何でもanyhow::Errorに吸収)、eyre(anyhow + レポーターをカスタマイズ)、miette(綺麗な診断出力)。
典型的なライブラリ層/アプリ層の分離例。
// ライブラリ層:thiserror で明示的なエラー型
use thiserror::Error;
#[derive(Debug, Error)]
pub enum BillingError {
#[error("invoice not found: {0}")]
NotFound(i64),
#[error("database error")]
Db(#[from] sqlx::Error),
#[error("payment provider error: {0}")]
Provider(String),
}
pub async fn charge(invoice_id: i64) -> Result<(), BillingError> {
Err(BillingError::Provider("stripe timeout".into()))
}
// アプリ層:anyhow でコンテキストを積み重ねる
use anyhow::Context;
pub async fn process_batch(ids: &[i64]) -> anyhow::Result<()> {
for &id in ids {
charge(id).await
.with_context(|| format!("failed to charge invoice {id}"))?;
}
Ok(())
}
miette はコンパイラの診断のようにソース位置を指し示す出力を作る。CLI をユーザーフレンドリにするときに重宝する。
tracing + tracing-subscriber — 非同期オブザーバビリティの標準
println!/log/env_logger の時代を越え、2026 年の Rust の観測標準は tracing だ。tokio チーム製で非同期コードに自然に馴染む。
use tracing::{info, instrument, error};
use tracing_subscriber::{EnvFilter, fmt, prelude::*};
#[instrument(skip(pool))]
async fn handle_request(pool: &sqlx::PgPool, user_id: i64) -> anyhow::Result<()> {
info!(user_id, "processing request");
let _row = sqlx::query("SELECT 1").fetch_one(pool).await?;
Ok(())
}
#[tokio::main]
async fn main() {
tracing_subscriber::registry()
.with(EnvFilter::try_from_default_env().unwrap_or_else(|_| "info".into()))
.with(fmt::layer().json())
.init();
info!("server starting");
}
tracing-opentelemetry アダプタを足せばスパンを OTEL トレーサへそのまま流し込めるし、tracing-loki/tracing-bunyan-formatter などエクスポーター類も豊富だ。
2026 年の serde — 依然として標準、miniserde や postcard
serde は事実上の標準シリアライゼーションフレームワーク。2026 年 5 月時点で 1.0 系がメンテされ続けており、「serde 2.0」の RFC は議論中だがまだ安定リリースはない。
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug)]
struct ApiResponse {
#[serde(rename = "userId")]
user_id: i64,
#[serde(default)]
tags: Vec<String>,
#[serde(skip_serializing_if = "Option::is_none")]
email: Option<String>,
}
fn parse_response(s: &str) -> serde_json::Result<ApiResponse> {
serde_json::from_str(s)
}
代替候補:
- miniserde:マクロのコンパイル時間を大幅に削った最小シリアライザ。JSON 専用。
- postcard:
serdeベースで組込ターゲットに向くバイナリ形式。no_std対応。 - bincode 2.0:標準的な高速バイナリ。derive マクロは別パッケージへ分離。
- rkyv:ゼロコピーデシリアライズ。性能最優先用途。
Tauri 2 — デスクトップとモバイルを同じコードで
Tauri 1 が「軽量な Electron 代替」だったのに対し、Tauri 2(2024 年に GA、2026 年 5 月時点で安定トラック)は、同じ Rust コアの上にデスクトップ+ Android + iOS を束ねる。
// src-tauri/src/lib.rs
use tauri::command;
#[command]
async fn greet(name: String) -> Result<String, String> {
Ok(format!("Hello, {name}!"))
}
#[command]
async fn read_file(path: String) -> Result<String, String> {
tokio::fs::read_to_string(&path).await.map_err(|e| e.to_string())
}
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
tauri::Builder::default()
.plugin(tauri_plugin_shell::init())
.invoke_handler(tauri::generate_handler![greet, read_file])
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
プラグイン体系が整い、tauri-plugin-sql、tauri-plugin-store、tauri-plugin-deep-link、tauri-plugin-notification などのファーストパーティプラグインがモバイルまでカバーする。フロントエンドは Vanilla / React / Vue / Svelte / Leptos / Dioxus いずれも可能。
Leptos / Dioxus / Yew / Sycamore — Rust フルスタックフロントエンド
WASM + Rust のフルスタックフレームワークは 4 系統に分かれる。
- Leptos 0.7+:シグナルベースの fine-grained リアクティビティ、SSR / CSR / ハイドレーション/
server fnを一級サポート。cargo-leptosでフルスタックビルド。 - Dioxus 0.6+:RSX(React 風)マクロ、デスクトップ/モバイル/Web/TUI のマルチターゲット。2025 年に Dioxus チームがフルタイム OSS 企業として活動を開始。
- Yew:クラシックな VDOM。導入は簡単だがフルスタックツールは Leptos に劣る。
- Sycamore:Solid 影響のシグナルベース。学習用や小規模 SPA 向け。
Leptos のフルスタックコンポーネントの例。
use leptos::*;
use leptos::server_fn::ServerFn;
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Clone)]
pub struct Todo { pub id: i64, pub title: String, pub done: bool }
#[server]
pub async fn list_todos() -> Result<Vec<Todo>, ServerFnError> {
Ok(vec![Todo { id: 1, title: "ship".into(), done: false }])
}
#[component]
pub fn TodoList() -> impl IntoView {
let todos = create_resource(|| (), |_| async move { list_todos().await });
view! {
<Suspense fallback=move || view! { <p>"Loading..."</p> }>
{move || todos.get().map(|res| match res {
Ok(items) => view! {
<ul>{items.into_iter().map(|t| view!{ <li>{t.title}</li> }).collect_view()}</ul>
}.into_view(),
Err(_) => view! { <p>"error"</p> }.into_view(),
})}
</Suspense>
}
}
同じ画面を Dioxus で書くと。
use dioxus::prelude::*;
#[derive(Clone, PartialEq, Props)]
struct Todo { id: i64, title: String, done: bool }
fn TodoList(cx: Scope) -> Element {
let todos = use_state(cx, || vec![Todo { id: 1, title: "ship".into(), done: false }]);
cx.render(rsx! {
ul {
todos.iter().map(|t| rsx!{
li { key: "{t.id}", "{t.title}" }
})
}
})
}
| フレームワーク | パラダイム | マルチターゲット | フルスタック | 推奨 |
|---|---|---|---|---|
| Leptos | シグナル、SSR 一級 | Web | 強い | フルスタック Web 標準 |
| Dioxus | RSX、マルチレンダラ | Web / デスクトップ / モバイル / TUI | 整備中 | マルチターゲット |
| Yew | VDOM | Web | 弱い | 学習/単純 SPA |
| Sycamore | シグナル | Web | 弱い | 学習用 |
egui / Iced / Slint — ネイティブ GUI ライブラリ
Tauri が「WebView ベース」なのに対し、ネイティブ GUI は三択。
- egui:イミディエイトモード GUI。独自レンダラ(
eframe)、短いコード、ゲーム内 UI や社内ツールに最適。 - Iced:Elm 影響の Cmd/Sub パターン。デスクトップアプリ向け。
- Slint:DSL(
.slintファイル)ベース。組込にやさしく、商用ライセンスも提供。
use eframe::egui;
struct App { name: String, age: u32 }
impl eframe::App for App {
fn update(&mut self, ctx: &egui::Context, _: &mut eframe::Frame) {
egui::CentralPanel::default().show(ctx, |ui| {
ui.heading("My egui Application");
ui.horizontal(|ui| {
ui.label("Your name: ");
ui.text_edit_singleline(&mut self.name);
});
ui.add(egui::Slider::new(&mut self.age, 0..=120).text("age"));
if ui.button("Increment").clicked() { self.age += 1; }
ui.label(format!("Hello '{}', age {}", self.name, self.age));
});
}
}
fn main() -> eframe::Result<()> {
let opts = eframe::NativeOptions::default();
eframe::run_native(
"demo",
opts,
Box::new(|_| Ok(Box::new(App { name: "Arthur".into(), age: 42 }))),
)
}
| ライブラリ | パラダイム | レンダラ | 向いている用途 |
|---|---|---|---|
| egui | イミディエイトモード | wgpu / glow | ゲーム内デバッグ、社内ツール |
| Iced | Elm 風 retained | wgpu / tiny-skia | デスクトップアプリ |
| Slint | DSL retained | software / skia / femtovg | 組込、キオスク |
| Dioxus desktop | WebView | OS WebView | Web 資産の再利用 |
| Tauri 2 | WebView | OS WebView | フルデスクトップ+モバイル |
Bevy 0.15+ — 事実上の標準となった Rust ゲームエンジン
Bevy はデータ指向 ECS のゲームエンジン。2025 年の 0.15 で BSN(Bevy Scene Notation)、レンダーグラフ v2、UI 改修が入り、2026 年の 0.16 / 0.17 系ではエディタ、ホットリロード、追加マテリアルが進む。
use bevy::prelude::*;
#[derive(Component)]
struct Player { speed: f32 }
fn spawn_player(mut commands: Commands) {
commands.spawn((
Player { speed: 250.0 },
Sprite::from_color(Color::srgb(0.2, 0.7, 1.0), Vec2::new(40.0, 40.0)),
Transform::default(),
));
}
fn move_player(
time: Res<Time>,
keys: Res<ButtonInput<KeyCode>>,
mut q: Query<(&Player, &mut Transform)>,
) {
for (p, mut t) in &mut q {
let mut dir = Vec3::ZERO;
if keys.pressed(KeyCode::KeyW) { dir.y += 1.0; }
if keys.pressed(KeyCode::KeyS) { dir.y -= 1.0; }
if keys.pressed(KeyCode::KeyA) { dir.x -= 1.0; }
if keys.pressed(KeyCode::KeyD) { dir.x += 1.0; }
t.translation += dir.normalize_or_zero() * p.speed * time.delta_secs();
}
}
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_systems(Startup, spawn_player)
.add_systems(Update, move_player)
.run();
}
Bevy の魅力は「ECS が一級市民で、システムが単なる関数」であること。ゲームだけでなくシミュレーションやツールのバックエンドにも採用が広がっている。
Embassy / RTIC / embedded-hal — 組込/ファームウェアの Rust
no_std 組込領域での 2026 年の流れははっきりしている。Embassy が事実上の標準で、割り込み優先度ベースの決定論が必要な場面では RTIC が選ばれる。
#![no_std]
#![no_main]
use embassy_executor::Spawner;
use embassy_rp::gpio::{Level, Output};
use embassy_time::{Duration, Timer};
use {defmt_rtt as _, panic_probe as _};
#[embassy_executor::task]
async fn blink(mut led: Output<'static>) {
loop {
led.set_high();
Timer::after(Duration::from_millis(500)).await;
led.set_low();
Timer::after(Duration::from_millis(500)).await;
}
}
#[embassy_executor::main]
async fn main(spawner: Spawner) {
let p = embassy_rp::init(Default::default());
let led = Output::new(p.PIN_25, Level::Low);
spawner.spawn(blink(led)).unwrap();
}
embedded-hal 1.0(2023 年末安定化)の登場でドライバ生態系が一本化された。STM32 / RP2040 / nRF52 / ESP32 を問わず、embedded-hal トレイトを実装した HAL の上で同じドライバが動く。
CLI とシステムツール — clap 4.5 / argh / ripgrep / bat / fd
CLI パーサは事実上 clap が標準。
use clap::{Parser, Subcommand};
#[derive(Parser)]
#[command(name = "blogctl", version, about = "Blog management CLI")]
struct Cli {
#[command(subcommand)]
command: Cmd,
}
#[derive(Subcommand)]
enum Cmd {
/// Create a new post
New { title: String, #[arg(short, long)] draft: bool },
/// Publish a post
Publish { slug: String },
}
fn main() {
let cli = Cli::parse();
match cli.command {
Cmd::New { title, draft } => println!("new post: {title} (draft={draft})"),
Cmd::Publish { slug } => println!("publish {slug}"),
}
}
argh(Google)は derive マクロのコンパイル時間が短く、小規模ツールに向く。システムコマンドラインツールでは ripgrep、fd、bat、eza、zoxide、bottom、dust、procs、hyperfine、tokei、mdbook などが Rust 製のデファクトになっている。
Cargo ワークスペース/build.rs/クロスコンパイル
大規模 Rust プロジェクトはワークスペースでクレートを束ねる。
# ワークスペースルートの Cargo.toml
[workspace]
resolver = "3"
members = ["crates/api", "crates/domain", "crates/storage"]
[workspace.dependencies]
tokio = { version = "1.40", features = ["full"] }
sqlx = { version = "0.8", features = ["runtime-tokio-rustls", "postgres"] }
axum = "0.8"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
thiserror = "1"
anyhow = "1"
[profile.release]
opt-level = 3
lto = "thin"
codegen-units = 1
strip = "symbols"
クロスコンパイルは cross クレートが標準。cross build --target aarch64-unknown-linux-musl --release の一行で Docker ベースのツールチェーンが静的バイナリを生成する。
Cargo ツール群 — nextest / mutants / deny / audit / machete / expand / binstall
標準の cargo test だけでは足りない。2026 年標準の補助ツール群は次の通り。
| ツール | 用途 |
|---|---|
| cargo-nextest | 並列テストランナー、洗練された出力、隔離 |
| cargo-mutants | ミューテーションテストでテスト品質を検証 |
| cargo-deny | ライセンス/脆弱性/重複依存のチェック |
| cargo-audit | RUSTSEC DB ベースの脆弱性スキャン |
| cargo-machete | 未使用依存の検出 |
| cargo-expand | マクロ展開後のコードを確認 |
| cargo-binstall | プリビルドバイナリのインストール |
| cargo-watch | ファイル変更で自動再ビルド |
| cargo-leptos | Leptos のフルスタックビルド |
# 標準 CI セット
cargo fmt --all -- --check
cargo clippy --all-targets --all-features -- -D warnings
cargo nextest run --workspace --all-features
cargo deny check
cargo audit
cargo machete
WebAssembly — wasm-bindgen / wasm-pack / wasmtime / wasmer
Rust + WASM は二つの陣営に分かれる。
- ブラウザ向け:
wasm-bindgen+wasm-pack。JS と Rust の自動バインディング。 - サーバー/エッジ向け:
wasmtime(Bytecode Alliance、Fastly や Microsoft が支援)、wasmer。2024 年に WASI Preview 2 が定着し、コンポーネントモデルベースのモジュール化が進行中。
Cloudflare Workers は Rust + WASM を一級市民として扱い、Fermyon/Spin/WasmCloud のような企業が WASM ベースのサーバーレスを前進させている。
rust-for-linux / Cloudflare Pingora / Discord / Dropbox / Figma — 本番事例
Rust の採用はもはや「スタートアップの実験」ではない。
| 企業/プロジェクト | 時期 | Rust の使われ方 | インパクト |
|---|---|---|---|
| Linux Kernel | 2022 マージ、2024 メインライン拡大 | ドライバ、Android Binder | システム言語としての公認 |
| Cloudflare Pingora | 2022 発表、2024 OSS 化 | 次世代 HTTP プロキシ(NGINX 置換) | 1 日 40 兆件超 |
| Discord | 2020〜 | Read States、ゲートウェイ | GC ポーズ排除、99.99% 安定性 |
| Dropbox | 2014〜 | Magic Pocket ストレージ | エクサバイト級 |
| Figma | 2022〜 | マルチプレイヤー HTTP レイヤー | 同時編集の性能 |
| Mozilla / Servo | 2024 LF 移管 | 次世代ブラウザエンジン | 組込ブラウザ |
| AWS | 全社規模 | Firecracker、Bottlerocket、S3 一部 | コンテナ/microVM |
| Android | Binder、クラッシュサブシステム | システムのメモリ安全 | |
| Microsoft | Windows | 一部システムコンポーネント | メモリ安全の強化 |
| Meta | バックエンド | サービスメッシュの一部 | 公式採用 |
落とし穴とトレードオフ — Rust 導入時にハマりやすい罠
新規プロジェクトに Rust を導入する際によく見る落とし穴を 5 つ。
- コンパイル時間:大規模ワークスペースのフルビルドは長い。
cargo check中心のワークフロー、sccache、moldリンカ、debug-info=line-tables-onlyの組み合わせが標準。 - async + Send 境界:
Box<dyn Trait>を多用しない。ライブラリのトレイトは可能な限りSend + 'static境界を明示する。 - dyn 互換性と RPITIT:全 async-trait を RPITIT に移すと dyn-trait が壊れる。
dynで使うトレイトは引き続きasync-traitマクロが必要な場合がある。 - エラー型の肥大化:1 つのライブラリに巨大な
enum Errorを詰め込まない。モジュールごとに小さなエラー型を置き、Fromで引き上げる。 - unsafe の濫用:99% のコードに
unsafeは不要。FFI/組込/SIMD でなければ立ち止まって見直す。
韓国・日本での Rust 採用 — Naver / Kakao / サイバーエージェント / メルカリ / Sansan
韓国・日本も積極的だ。
- ネイバー:検索/広告の一部バックエンドやメディア処理パイプラインに Rust を導入。社内 Rust 勉強会・セミナーが定期開催されている。
- カカオブレイン/カカオエンタープライズ:ML 推論サーバーやモデルゲートウェイで Rust を活用。PyO3 で Python と統合。
- Discord Korea / Twitch Korea グループ:グローバルの Rust スタックをそのまま採用。
- サイバーエージェント:広告/ゲーム基盤の一部を Rust にリライト。AbemaTV の一部マイクロサービス。
- メルカリ:検索、社内インフラツール、CLI を Rust で実装。Rust ロールの採用も常時。
- Sansan:名刺認識/OCR の後処理パイプラインに Rust を採用。
- LINE ヤフー:システムデーモンやビルドツールを Rust に移行。
東京・ソウルとも四半期ごとに Rust ミートアップが行われる。韓国には「Rust Korea」の Slack / Discord / Facebook グループ、日本には定例の「Rust.Tokyo」カンファレンスが定着している。
Rust を学ぶ順序 — 2026 年版ロードマップ
初めて Rust を触る開発者におすすめの流れ。
- The Rust Programming Language(「the book」) 1〜10 章:所有権、借用、ライフタイムの直感をつかむ。
- rustlings:小さな穴埋め問題でコンパイラのメッセージに慣れる。
cargo newで CLI:clap + serde + anyhow の組み合わせ。- tokio + axum で小さな API:sqlx + Postgres + tracing まで。
- 2024 エディションの変更点と async fn in trait を学習。
- ドメインを選ぶ:
- Web/フルスタック:Leptos か Dioxus。
- デスクトップ:Tauri 2 か egui。
- ゲーム:Bevy。
- 組込:Embassy + RP2040 か STM32 Discovery。
- システム:rust-for-linux、Firecracker、Pingora のソースを読む。
「速く書く」より「コンパイラと対話してモデルを作る」が肝。コンパイラエラーは友達だ。
まとめ — 2026 年の Rust は「選択肢」ではなく「デフォルト」
2024 年の rust-for-linux マージ、2024 年の Tauri 2 GA、2025 年の Pingora OSS 化、2025 年の axum 0.8、2026 年の Rust 1.85(2024 エディション)と点を結ぶと、2026 年 5 月の Rust はもはや「使うとよい言語」ではない。バックエンドは tokio + axum + sqlx、デスクトップ/モバイルは Tauri 2、ゲームは Bevy、組込は Embassy、フルスタック Web は Leptos / Dioxus がデフォルトになった。
問いはもはや「Rust を使うべきか?」ではなく「どこで Rust を使うか?」である。そしてその答えはどんどん広がり続けている。
References
- Rust 公式 — https://www.rust-lang.org/
- The Rust Book — https://doc.rust-lang.org/book/
- Rust ブログ — https://blog.rust-lang.org/
- tokio — https://tokio.rs/
- axum — https://github.com/tokio-rs/axum
- actix-web — https://actix.rs/
- sqlx — https://github.com/launchbadge/sqlx
- Diesel — https://diesel.rs/
- SeaORM — https://www.sea-ql.org/SeaORM/
- Bevy — https://bevyengine.org/
- Tauri — https://tauri.app/
- Leptos — https://leptos.dev/
- Dioxus — https://dioxuslabs.com/
- Yew — https://yew.rs/
- Embassy — https://embassy.dev/
- crates.io — https://crates.io/
- rust-for-linux — https://rust-for-linux.com/
- Cloudflare Pingora — https://github.com/cloudflare/pingora
- Servo (Linux Foundation) — https://servo.org/
- Discord Rust 事例 — https://discord.com/blog/why-discord-is-switching-from-go-to-rust