Skip to content
Published on

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

Authors

はじめに — 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 レイヤーに分かれる。

  1. 言語/ツールチェーン:rustc、cargo、rustup、rust-analyzer
  2. async ランタイム:tokio が事実上の標準。async-std / smol / embassy はニッチ
  3. Web/ネットワーク:axum、actix-web 5、poem、rocket 0.5、warp、salvo、loco-rs
  4. データ/ORM:sqlx、sea-orm、diesel 2.x、rbatis
  5. エラー/オブザーバビリティ:anyhow、thiserror、eyre、snafu、miette、tracing
  6. GUI/レンダリング:Tauri 2、egui、Iced、Slint、Dioxus、Yew、Leptos、Sycamore
  7. システム/組込/ゲーム:Embassy、RTIC、embedded-hal、Bevy、winit、gtk-rs
  8. ツール群: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-threadmio(epoll / kqueue / IOCP)2026 年の事実上の標準
async-stdシンプル API 指向multi-threadsmol ベースメンテモード、新規採用は非推奨
smol軽量(約 1k LOC)single / multipolling / async-io組込/学習用途
embassyno_std / ファームウェア協調的、no-alloc 可HAL 統合RP2040 / STM32 / ESP32
glommioLinux 限定 io_uringthread-per-coreio_uringDB/ストレージ

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 + バックグラウンドジョブ + メーラーをフルスタックで束ねる。
フレームワーク主な特徴推奨シナリオ
axumtower エコシステム、エクストラクタバックエンド標準
actix-web 5最上位のスループット超高性能ゲートウェイ
poemOpenAPI が一級市民スキーマ駆動 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_URLsqlx-data.json(オフラインモード)でスキーマを参照する。CI ではオフラインモードを使うのが標準だ。

クレートスタイル安全性async推奨用途
sqlxSQL 優先 + マクロ検査コンパイル時ネイティブバックエンド標準
sea-ormActiveRecord ORMランタイムネイティブフルスタック/loco-rs
diesel型付き DSLコンパイル時最強アダプタ要安全性最優先
rbatisXML / マクロ 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!logenv_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-lokitracing-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 専用。
  • postcardserde ベースで組込ターゲットに向くバイナリ形式。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-sqltauri-plugin-storetauri-plugin-deep-linktauri-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 標準
DioxusRSX、マルチレンダラWeb / デスクトップ / モバイル / TUI整備中マルチターゲット
YewVDOMWeb弱い学習/単純 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ゲーム内デバッグ、社内ツール
IcedElm 風 retainedwgpu / tiny-skiaデスクトップアプリ
SlintDSL retainedsoftware / skia / femtovg組込、キオスク
Dioxus desktopWebViewOS WebViewWeb 資産の再利用
Tauri 2WebViewOS 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 マクロのコンパイル時間が短く、小規模ツールに向く。システムコマンドラインツールでは ripgrepfdbatezazoxidebottomdustprocshyperfinetokeimdbook などが 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-auditRUSTSEC DB ベースの脆弱性スキャン
cargo-machete未使用依存の検出
cargo-expandマクロ展開後のコードを確認
cargo-binstallプリビルドバイナリのインストール
cargo-watchファイル変更で自動再ビルド
cargo-leptosLeptos のフルスタックビルド
# 標準 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 Kernel2022 マージ、2024 メインライン拡大ドライバ、Android Binderシステム言語としての公認
Cloudflare Pingora2022 発表、2024 OSS 化次世代 HTTP プロキシ(NGINX 置換)1 日 40 兆件超
Discord2020〜Read States、ゲートウェイGC ポーズ排除、99.99% 安定性
Dropbox2014〜Magic Pocket ストレージエクサバイト級
Figma2022〜マルチプレイヤー HTTP レイヤー同時編集の性能
Mozilla / Servo2024 LF 移管次世代ブラウザエンジン組込ブラウザ
AWS全社規模Firecracker、Bottlerocket、S3 一部コンテナ/microVM
GoogleAndroidBinder、クラッシュサブシステムシステムのメモリ安全
MicrosoftWindows一部システムコンポーネントメモリ安全の強化
Metaバックエンドサービスメッシュの一部公式採用

落とし穴とトレードオフ — Rust 導入時にハマりやすい罠

新規プロジェクトに Rust を導入する際によく見る落とし穴を 5 つ。

  1. コンパイル時間:大規模ワークスペースのフルビルドは長い。cargo check 中心のワークフロー、sccachemold リンカ、debug-info=line-tables-only の組み合わせが標準。
  2. async + Send 境界Box<dyn Trait> を多用しない。ライブラリのトレイトは可能な限り Send + 'static 境界を明示する。
  3. dyn 互換性と RPITIT:全 async-trait を RPITIT に移すと dyn-trait が壊れる。dyn で使うトレイトは引き続き async-trait マクロが必要な場合がある。
  4. エラー型の肥大化:1 つのライブラリに巨大な enum Error を詰め込まない。モジュールごとに小さなエラー型を置き、From で引き上げる。
  5. 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 を触る開発者におすすめの流れ。

  1. The Rust Programming Language(「the book」) 1〜10 章:所有権、借用、ライフタイムの直感をつかむ。
  2. rustlings:小さな穴埋め問題でコンパイラのメッセージに慣れる。
  3. cargo new で CLI:clap + serde + anyhow の組み合わせ。
  4. tokio + axum で小さな API:sqlx + Postgres + tracing まで。
  5. 2024 エディションの変更点と async fn in trait を学習。
  6. ドメインを選ぶ:
    • 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