Ecosystem
Rust’s crate ecosystem is mature for systems programming, web services, and CLI tools. Here are the go-to libraries organized by category.
Web Frameworks
axum (preferred)
Built on Tokio and Tower. Modular, composable, strong typing.
use axum::{routing::get, Router, Json, extract::Path};
use serde::Serialize;
#[derive(Serialize)]
struct User {
id: u32,
name: String,
}
async fn get_user(Path(id): Path<u32>) -> Json<User> {
Json(User { id, name: "Alice".into() })
}
#[tokio::main]
async fn main() {
let app = Router::new()
.route("/users/{id}", get(get_user));
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
axum::serve(listener, app).await.unwrap();
}
[dependencies]
axum = "0.8"
tokio = { version = "1", features = ["full"] }
serde = { version = "1", features = ["derive"] }
actix-web
Higher raw throughput in benchmarks, actor-based model. More mature but less idiomatic.
use actix_web::{web, App, HttpServer, HttpResponse};
async fn hello() -> HttpResponse {
HttpResponse::Ok().body("Hello!")
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(|| App::new().route("/", web::get().to(hello)))
.bind("0.0.0.0:3000")?
.run()
.await
}
| Framework | Best for | Notes |
|---|---|---|
| axum | New projects, idiomatic Rust | Built on Tower middleware ecosystem |
| actix-web | Maximum throughput, existing projects | Larger API surface, actor model |
CLI
clap v4
The standard for argument parsing. Derive macros generate the parser from a struct.
use clap::Parser;
#[derive(Parser)]
#[command(version, about = "A fast file processor")]
struct Cli {
/// Input file path
input: String,
/// Output format
#[arg(short, long, default_value = "json")]
format: String,
/// Enable verbose output
#[arg(short, long)]
verbose: bool,
}
See CLI Tool quickstart for a full walkthrough.
Serialization
serde
The universal serialization framework. Nearly every Rust library uses it.
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug)]
struct Config {
host: String,
port: u16,
#[serde(default)]
debug: bool,
#[serde(rename = "maxConnections")]
max_connections: Option<u32>,
}
// JSON
let json = serde_json::to_string_pretty(&config)?;
let config: Config = serde_json::from_str(&json)?;
// TOML
let toml = toml::to_string(&config)?;
let config: Config = toml::from_str(&toml)?;
| Format crate | Format |
|---|---|
serde_json | JSON |
toml | TOML |
serde_yaml | YAML |
csv | CSV |
bincode | Binary (compact, fast) |
Error Handling
| Crate | Purpose | Use when |
|---|---|---|
anyhow | Easy error propagation with context | Application code, CLIs, scripts |
thiserror | Define custom error types with derive | Library code, public APIs |
See Error Handling for detailed usage.
HTTP Client
reqwest
Async HTTP client built on Tokio. Supports JSON, TLS, cookies, proxies.
use reqwest::Client;
use serde::Deserialize;
#[derive(Deserialize)]
struct Repo {
name: String,
stargazers_count: u32,
}
async fn fetch_repo(owner: &str, repo: &str) -> anyhow::Result<Repo> {
let client = Client::new();
let repo = client
.get(format!("https://api.github.com/repos/{owner}/{repo}"))
.header("User-Agent", "rust-app")
.send()
.await?
.json::<Repo>()
.await?;
Ok(repo)
}
[dependencies]
reqwest = { version = "0.12", features = ["json"] }
Tip: Reuse
Clientinstances. Creating a new client per request is wasteful - it sets up a new connection pool each time.
Database
sqlx - compile-time checked SQL
use sqlx::postgres::PgPoolOptions;
#[derive(sqlx::FromRow)]
struct User {
id: i32,
name: String,
email: String,
}
async fn get_users(pool: &sqlx::PgPool) -> anyhow::Result<Vec<User>> {
let users = sqlx::query_as::<_, User>("SELECT id, name, email FROM users WHERE active = $1")
.bind(true)
.fetch_all(pool)
.await?;
Ok(users)
}
diesel - ORM with query builder
use diesel::prelude::*;
#[derive(Queryable)]
struct User {
id: i32,
name: String,
email: String,
}
fn get_users(conn: &mut PgConnection) -> QueryResult<Vec<User>> {
users::table
.filter(users::active.eq(true))
.load(conn)
}
| Crate | Style | Best for |
|---|---|---|
| sqlx | Raw SQL, compile-time checked | Projects that prefer SQL, need flexibility |
| diesel | Query builder / ORM | Type-safe query composition, migrations |
Async Runtime
Tokio
The standard async runtime. Used by axum, reqwest, sqlx, and most of the async ecosystem.
[dependencies]
tokio = { version = "1", features = ["full"] }
See Async Rust for detailed patterns.
Other Essential Crates
| Crate | Purpose | Example use |
|---|---|---|
tracing | Structured logging | tracing::info!(user_id = 42, "request handled") |
chrono | Date and time | Utc::now(), parsing, formatting |
uuid | UUID generation | Uuid::new_v4() |
regex | Regular expressions | Regex::new(r"\d+")? |
rayon | Data parallelism | vec.par_iter().map(...) (drop-in parallel iterators) |
rand | Random number generation | rand::random::<u32>() |
tower | Middleware framework | Timeouts, rate limiting, retries for services |
bytes | Efficient byte buffers | Zero-copy networking, protocol parsing |
Rust vs Go
Both are modern systems-adjacent languages. Here’s how they compare:
| Aspect | Rust | Go |
|---|---|---|
| Memory | Ownership, no GC | Garbage collected |
| Concurrency | async/await + Tokio | goroutines + channels (built-in) |
| Error handling | Result<T,E>, ? operator | Multiple return values, if err != nil |
| Type system | Generics, traits, enums | Interfaces, generics (since 1.18) |
| Compile speed | Slow (minutes for large projects) | Fast (seconds) |
| Runtime performance | Faster (no GC pauses, zero-cost abstractions) | Fast (but GC pauses under load) |
| Learning curve | Steep (ownership, lifetimes) | Gentle (simple by design) |
| Best for | Performance-critical, correctness-critical | Microservices, DevOps tools, quick iteration |
| Binary size | Small (static by default) | Larger (includes runtime + GC) |
| Ecosystem | crates.io, Cargo | Go modules, go get |
| Null safety | Option<T> (no null) | nil (can panic at runtime) |
Tip: Choose Go when you need fast iteration and simple concurrency. Choose Rust when you need maximum performance, memory safety guarantees, or are building something that can’t afford GC pauses (embedded, game engines, databases).
Finding Crates
- crates.io - Official package registry
- lib.rs - Better search and categorization
- blessed.rs - Curated list of recommended crates by category
cargo add <crate>- Search and add from the command line
Tip: Check download counts and last-updated dates on crates.io. A crate with millions of downloads and recent updates is usually a safe bet. Avoid crates that haven’t been updated in over a year unless they’re feature-complete (like
regex).
Next: Async Rust | Gotchas