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는 "유망한 언어"에서 "리눅스 커널이 채택한 언어"로 신분이 바뀌었다. 2026년 5월 현재, 그 변화는 더 또렷하다. Cloudflare의 Pingora(Rust로 작성된 차세대 프록시)는 하루 40조 건이 넘는 요청을 처리하며, Discord의 Read States 서비스는 Rust 마이그레이션 이후 99.99% 안정성과 GC 폴 제거를 동시에 달성했고, Dropbox의 Magic Pocket 스토리지 엔진, Figma의 멀티플레이어 HTTP 레이어, Mozilla의 Servo(2024년 Linux Foundation으로 이관)가 Rust 기반으로 굳어졌다.

이 글은 마케팅 매트릭스가 아니라 "2026년 5월 현재 Rust 프로덕션 스택은 어떻게 구성되는가"를 정직하게 짚는다. 1.85 에디션의 변화부터 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. 웹/네트워크: axum, actix-web 5, poem, rocket 0.5, warp, salvo, loco-rs
  4. 데이터/ORM: sqlx, sea-orm, diesel 2.x, rbatis, sqlite-rs
  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 에디션에서 다양한 lints가 정리됐다.
  • let-else 패턴: 1.65부터 사용 가능. 2024 에디션에서 if let 임시 수명(temporary lifetime) 규칙이 직관적으로 변경됐다.
  • never type fallback: ! 타입의 폴백이 ()에서 !로 바뀌어 더 엄격해졌다. 일부 코드는 명시적 타입 어노테이션 필요.
  • 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로 줄었다. 즉, 한 태스크가 128번 폴(poll) 되면 자동으로 양보(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-based유지보수 모드, 신규 채택 비추
smol경량 (1k LOC)single/multipolling/async-io임베디드, 학습 목적
embassyno_std/펌웨어cooperative, no-alloc 가능HAL 통합RP2040/STM32/ESP32
glommioLinux-only io_uringthread-per-coreio_uring데이터베이스/스토리지

2026년 5월 기준 "라이브러리는 런타임 무관(runtime-agnostic)으로, 애플리케이션은 tokio로"가 표준 패턴이다. tokio::main을 라이브러리 크레이트에 박지 않는 게 매너다.

axum — async 웹 프레임워크의 사실상 표준

tokio 팀이 직접 만드는 axum은 0.7~0.8을 거치며 사실상 표준이 됐다. 특징은 tower::Service 기반 미들웨어, 강력한 추출기(extractor) 시스템, 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와 다른 웹 프레임워크들 — poem · rocket · warp · salvo · loco-rs

axum이 표준이라고 해도 다른 프레임워크도 살아 있다.

  • actix-web 5: 액터 모델은 점점 옅어지고 일반 async-fn 핸들러 중심으로 자리 잡았다. TechEmpower 벤치마크에서 여전히 최상위권. 마이크로벤치 성능을 짜내는 팀이 선호.
  • poem: tokio 위에 axum과 유사한 추출기 디자인. OpenAPI 자동 생성(poem-openapi)에 강점.
  • rocket 0.5: 1.0 트랙으로 안정화됐지만 async 적응이 느려 신규 채택은 감소.
  • warp: 필터 콤비네이터 디자인. 유지보수 활동은 줄었다.
  • salvo: 중국 커뮤니티에서 활발. 트리 기반 라우팅.
  • loco-rs: "Rust의 Rails"를 표방. 풀스택 어셈블리(axum + sea-orm + 백그라운드 작업 + 메일러).
프레임워크핵심 특징추천 시나리오
axumtower 생태계, 추출기일반 백엔드 표준
actix-web 5성능 최상위초고성능 게이트웨이
poemOpenAPI 1급 시민스키마 중심 API
loco-rs풀스택 컨벤션"Rails of Rust" 빠른 스타트
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(오프라인 모드)으로 DB 스키마를 미리 확인한다. CI에서 오프라인 모드를 쓰는 게 표준이다.

라이브러리스타일안전성async추천
sqlxSQL 우선 + 매크로 검사컴파일타임 검증네이티브백엔드 표준
sea-ormActiveRecord ORM런타임네이티브풀스택/loco-rs
diesel타입드 DSL컴파일타임 최강adapter 필요안전성 우선
rbatisXML/매크로 SQL런타임네이티브중국 시장 호환

에러 처리 — anyhow · thiserror · eyre · snafu · miette

에러 처리 크레이트는 두 축으로 갈린다.

  • 라이브러리용 에러 타입 정의: thiserror(파생 매크로), 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 같은 익스포터도 풍부하다.

serde 2026 — 표준의 자리, 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: zero-copy 역직렬화. 성능 극단 추구.

Tauri 2 — 데스크톱과 모바일을 같은 코드로

Tauri 1이 "Electron의 가벼운 대안"이었다면, Tauri 2(2024년 GA, 2026년 5월 안정 트랙)는 데스크톱 + 안드로이드 + iOS를 같은 Rust 코어로 묶는다.

// 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 같은 1급 플러그인이 모바일까지 커버한다. 프론트는 Vanilla/React/Vue/Svelte/Leptos/Dioxus 모두 가능.

Leptos · Dioxus · Yew · Sycamore — Rust 풀스택 프론트엔드

WASM + Rust 풀스택 프레임워크는 네 갈래다.

  • Leptos 0.7+: 시그널 기반 fine-grained 반응성, SSR/CSR/하이드레이션/server fn 일급 지원. cargo-leptos로 풀스택 빌드.
  • Dioxus 0.6+: RSX(React 유사) 매크로, 데스크톱/모바일/웹/터미널 멀티 타깃. 2025년 D팀이 풀타임 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 1급강함풀스택 웹 표준
DioxusRSX, 멀티 렌더러웹/데스크톱/모바일/TUI진행 중멀티 타깃
YewVDOM약함학습/단순 SPA
Sycamore시그널약함학습

egui · Iced · Slint — 네이티브 GUI 라이브러리

Tauri가 "웹뷰 기반"이라면, 네이티브 GUI는 세 갈래다.

  • egui: 즉시 모드(immediate mode) GUI. 자체 렌더러(eframe), 짧은 코드, 게임/내부 도구에 적합.
  • 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 }))),
    )
}
라이브러리패러다임렌더적합 시나리오
eguiimmediate modewgpu/glow게임 내 디버그, 내부 도구
IcedElm-like retainedwgpu/tiny-skia데스크톱 앱
SlintDSL retainedsoftware/skia/femtovg임베디드, 키오스크
Dioxus desktop웹뷰OS WebView웹 자산 재사용
Tauri 2웹뷰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 매크로 컴파일 시간이 짧아 작은 도구에 적합. 시스템 명령 라인 도구 중 Rust 작성이 사실상 표준이 된 사례는 ripgrep, fd, bat, eza, zoxide, bottom, dust, procs, hyperfine, tokei, mdbook이다.

Cargo 워크스페이스 · build.rs · cross-compile

대형 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. WASI Preview 2가 2024년 정착하면서 컴포넌트 모델 기반 모듈화가 진행 중.

Cloudflare Workers는 Rust+WASM을 1급 시민으로 지원하고, Fermyon·Spin·WasmCloud 같은 회사가 WASM 기반 서버리스를 끌어가고 있다.

rust-for-linux · Cloudflare Pingora · Discord · Dropbox · Figma — 프로덕션 사례

Rust 채택은 더 이상 "스타트업의 실험"이 아니다.

회사/프로젝트채택 시점Rust 사용처임팩트
Linux Kernel2022 머지, 2024 mainline 확장드라이버, Android Binder시스템 언어 인증
Cloudflare Pingora2022 발표, 2024 OSS차세대 HTTP 프록시 (NGINX 대체)일 40T 요청 처리
Discord2020~Read States, 게이트웨이GC pause 제거, 99.99% 안정성
Dropbox2014~Magic Pocket 스토리지엑사바이트급
Figma2022~멀티플레이어 HTTP 레이어동시 편집 성능
Mozilla / Servo2024 LF 이관차세대 브라우저 엔진임베디드 브라우저
AWS전사Firecracker, Bottlerocket, S3 일부컨테이너/마이크로VM
Google안드로이드Binder, Crash Subsystem시스템 메모리 안전
MicrosoftWindows일부 시스템 컴포넌트메모리 안전 강화
Meta백엔드서비스 메시 일부Rust 공식 채택

함정 · 트레이드오프 — Rust를 도입할 때 빠지기 쉬운 함정

Rust를 새 프로젝트에 도입할 때 자주 보는 함정 다섯 가지.

  1. 컴파일 시간: 큰 워크스페이스에서 풀 빌드는 길다. cargo check 위주 워크플로, sccache, mold 링커, 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. 에러 타입 폭주: 라이브러리 한 곳에 거대한 enum Error 박지 말 것. 모듈마다 작은 에러 타입을 두고 From으로 끌어올린다.
  5. unsafe 남용: 99% 의 코드는 unsafe가 필요 없다. FFI/임베디드/SIMD가 아니면 멈춰서 다시 본다.

한국 · 일본의 Rust 채택 — Naver · Kakao · CyberAgent · Mercari · Sansan

한국·일본도 적극적이다.

  • 네이버: 검색/광고 일부 백엔드, 미디어 처리 파이프라인에 Rust 도입. 사내 Rust 스터디·세미나가 정기 운영된다.
  • 카카오 브레인 / 카카오엔터프라이즈: ML 추론 서버, 모델 게이트웨이에 Rust 활용. PyO3로 파이썬과 결합.
  • Discord Korea / 트위치 코리아 그룹: 글로벌 Rust 스택을 그대로 활용.
  • CyberAgent: 광고·게임 인프라 일부를 Rust로 재작성. AbemaTV의 일부 마이크로서비스.
  • Mercari: 검색·인프라 도구·CLI 일부를 Rust로 작성. Rust 채용 공고 상시.
  • Sansan: 명함 인식·OCR 후처리 파이프라인에 Rust 채택.
  • LINE Yahoo: 일부 시스템 데몬, 빌드 도구를 Rust로 마이그레이션.

도쿄와 서울 모두 Rust 밋업이 분기마다 열린다. 한국은 "Rust Korea" 슬랙·디스코드·페이스북 그룹이, 일본은 "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. 도메인 선택:
    • 웹/풀스택: 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 오픈소스화, 2025년 axum 0.8, 2026년 Rust 1.85(2024 에디션)까지 흐름이 모이면, 2026년 5월 Rust는 더 이상 "쓰면 좋은 언어"가 아니다. 백엔드는 tokio + axum + sqlx, 데스크톱·모바일은 Tauri 2, 게임은 Bevy, 임베디드는 Embassy, 풀스택 웹은 Leptos/Dioxus가 표준이 됐다.

핵심은 더 이상 "Rust를 써야 하는가?"가 아니라 "어디에 Rust를 쓰는가?"다. 그리고 그 답은 점점 더 많은 영역으로 확장되고 있다.

References