Where to Go From Here
You now have a working mental model of the Rust backend stack: async execution under Tokio, HTTP with Axum and Tower, data persistence with SQLx, authentication patterns, a principled approach to errors, structured configuration, observability, and deployment. That's a real backend service.
What you've also accumulated, without necessarily noticing, is an intuition for why the design is the way it is. Axum's extractors make sense because FromRequest is a trait that anything can implement. Error handling is clear because thiserror and anyhow serve different purposes. Async works the way it does because futures are state machines, not threads.
This section is about where to go deeper.
Things Not Covered Here
WebSockets: Axum has built-in WebSocket support via axum::extract::ws. The upgrade dance is handled for you; you write the message handling logic. Works well with Tokio's broadcast channels for pub/sub patterns.
gRPC: The tonic crate is the standard for gRPC in Rust. It generates Rust code from .proto files and integrates with the Tokio ecosystem. If you're building internal service-to-service APIs or you need bidirectional streaming, it's worth knowing.
Message queues: lapin for AMQP (RabbitMQ), rdkafka for Kafka, aws-sdk-sqs for SQS. The async patterns are the same as everything else. Background workers are typically tokio::spawned tasks consuming from a channel.
Background jobs: apalis is a job queue library built for Rust that supports PostgreSQL, Redis, and SQLite as storage backends. For simpler needs, a tokio::spawned loop with a Tokio channel works fine.
Rate limiting: tower-governor or axum-governor provide rate limiting middleware based on the governor crate. Integrate at the router level before your handlers.
Caching: moka is a high-performance in-memory cache for Rust. For distributed caching, redis-rs (or deadpool-redis for async connection pooling) is the standard choice.
GraphQL: async-graphql integrates with Axum and Tokio. It's well-maintained and feature-complete. If you need GraphQL, it's the right choice.
The Crates Worth Knowing
Beyond what's in this book:
serde_with— extra serialization adapters for serde (serialize UUIDs as strings, durations in various formats, etc.)validator— derive-based input validationgarde— a newer validation crate with a cleaner APIonce_cell/std::sync::OnceLock— lazy initialization for static datadashmap— concurrent HashMap without needing a Mutexbytes— theBytestype used throughout the async ecosystem for zero-copy byte manipulationreqwest— async HTTP client (the standard choice for making outbound HTTP calls)tokio-retry— retry logic for fallible async operationsbackoff— exponential backoff strategies
Resources That Are Actually Good
The Tokio tutorial (tokio.rs/tokio/tutorial) — the best explanation of how Tokio works from the people who built it. Read the "Select" and "Streams" chapters if you haven't.
Jon Gjengset's videos — "Crust of Rust" on YouTube. If you want to understand the machinery behind async, his video on async/await fundamentals builds the executor from scratch.
The axum examples directory on GitHub — the official examples cover JWT auth, multipart forms, WebSockets, static file serving, and more. When you want to do something specific with Axum, start there.
"Zero To Production In Rust" by Luca Palmieri — a full-length book about building a production email newsletter service in Rust. Goes deeper on testing and deployment than this book does. Worth reading after you've got the basics.
The SQLx documentation and its GitHub issues — the compile-time query verification generates occasionally confusing errors. The GitHub issues are searchable and usually contain the answer.
A Note on Ecosystem Maturity
The Rust backend ecosystem in 2025 is genuinely production-ready. Axum is used by companies doing meaningful scale. SQLx is in production at places that care deeply about database correctness. Tokio is the foundation under all of it.
The ecosystem is also still evolving. Axum releases occasionally have breaking changes. SQLx 0.7 → 0.8 will have them too. The pattern throughout this book — pin your crate versions, understand what you're using, read the changelogs — is good practice precisely because the ecosystem is alive rather than fossilized.
The things that won't change: the async execution model, the error handling philosophy, the way Tower middleware composes, the guarantees that SQLx's compile-time checking provides. Learn the principles, and the API churn won't slow you down.
What Building in Rust Feels Like After a While
The compiler is not your adversary. It is your most pedantic colleague who has read every RFC and will not let you ship something subtly wrong. After you've been writing Rust for a while, the feeling of "it compiles" carries genuine informational weight — not certainty that the logic is correct, but confidence that a large class of errors has been ruled out before you ran a single test.
The trade-off is real: Rust is harder to write than Python or JavaScript. You spend more time on types and lifetimes and error conversions. In return, you get faster services, smaller deployments, and production issues that are structurally different from what you'd debug in a GC'd language. Whether the trade-off is worth it depends on what you're building.
For backend services with real reliability requirements, long service lifetimes, and teams who will maintain the code for years: it usually is.
Go build something.