Just added: Algorithms you can run and practice
Updated Jul 10, 2026 Edit on GitHub

Where to Go Next

Look back at the ground you covered. You can stand up an App and run it across worker threads with HttpServer, route a request to a handler, pull pieces out with extractors like Path, Query, Json, and web::Data, return anything that implements Responder, share a store across every worker without a global, wrap it in middleware, build full CRUD, and turn errors into clean responses with ResponseError - then test it with actix_web::test and tune it for production. That's a real REST API, not a toy.

The quieter win: the shape underneath actix-web is the same shape in every serious Rust web framework - an App of routes, run by an HttpServer, with handlers that extract from the request and return a Responder. Learn it once and you can read the others on sight. This last phase is the map: where actix-web sits among its neighbors, the layer you'll almost certainly add next, the root worth knowing, and one thing to go build.

actix-web vs the field

You now know enough to choose a framework on purpose rather than by reputation. The good news in Rust: the big three are all production-grade and all fast. The differences are about feel and what you build on, not whole different universes.

A line on each:

  • actix-web - the mature, batteries-included heavyweight, consistently at or near the top of the performance benchmarks: a long track record, a deep feature set (websockets, sessions, all in the box), and the web::Data/ResponseError patterns you just learned. (You are here.)
  • axum - the newer option from the Tokio team, tower-native and driven by the type system: plain async fn handlers, extractors as arguments, IntoResponse returns. Its superpower is the tower middleware ecosystem - reusable, and shared with gRPC via tonic. See axum From Zero.
  • Rocket - the most ergonomic, leaning hard on macros (#[get("/")] and friends) for concise handler code. See Rocket From Zero.

💡 How to pick: actix-web for maximum performance, maturity, and a big feature set out of the box. axum for the tower ecosystem and type-safe extractors. Rocket for concise, macro-driven code.

📝 Notice how much these three have converged - whichever you opened, you'd be writing the same thing: extract from the request, return a responder. Picking one is far less of a fork-in-the-road than it looks; none is "the best," the question is "best for this job."

The layer you'll add next: a real database

Every API in this guide kept its books in memory - perfect for learning, useless in production, since a restart wipes the data. The next thing almost every real actix-web service grows is a database.

Rust has no single default ORM. Three common answers, each with a clear personality:

  • sqlx - not an ORM, but the most popular companion. Write raw SQL; a macro checks your queries against a real database at compile time, so a typo'd column is a build error, not a 500 at 3am. Fully async.
  • SeaORM - a proper async ORM built on sqlx, for entities, relations, and a query builder instead of hand-written SQL.
  • Diesel - the mature, established ORM with a rich type-safe query DSL. More sync-flavored roots, worth knowing if the rest of your stack is async.

The reassuring bit: your handlers barely change. Remember Phase 4's web::Data<T>? A sqlx::PgPool drops straight into that same slot. Handlers still extract the pool, run a query, and return a Responder - you're swapping the bottom layer, not rewriting the top.

💡 Don't forget what's in the box: websockets are a long-standing actix-web strength. The day you want live updates - a chat feed, a pushing dashboard - it's right there in the framework you already know.

The root: Tokio

actix-web doesn't float in the air. Underneath it, like every async Rust web framework, sits Tokio - the async runtime driving your async fns, scheduling work across worker threads, handling I/O. Every .await ultimately answers to it.

You don't need to study Tokio to ship. But the day you want to know why an extractor can pause and resume, or how workers really share a pool, that's the floor dropping away. See Tokio: The Async Runtime.

What to build

Reading more won't make this stick - building one real thing will. Take the articles API you grew across this guide and carry it home:

  • Swap the in-memory store for sqlx + Postgres so articles survive a restart. Drop a PgPool into web::Data, write a few compile-checked queries.
  • Add JWT (or session) auth middleware so each request proves who it is, and articles belong to a user - the Phase 5 pattern, aimed at a real job.
  • Wire up tracing for observability and a few metrics.
  • Tidy up config so secrets, the database URL, and the port come from the environment.
  • Deploy it somewhere you can hit from your phone.

If the articles API feels too familiar, build something new instead - a URL shortener, a notes API, or a tiny live chat that puts actix's websockets to use. Same muscles either way. Finishing one project completely teaches more than three more tutorials would.

The clear-eyed close

actix-web was never magic. Strip it back and it's ideas you now understand completely: an App of routes, run by an HttpServer, with handlers that extract from the request and return a Responder - wrapped in middleware, error-handled with ResponseError, sitting on Tokio.

That's mature, fast Rust, and you can read the machine now. Go finish the articles API, give it a real database, lock it behind auth, light it up with tracing, deploy it, and show someone. You're ready.

Recap

  1. You can ship a real actix-web API - routed, extracted, responded, state-shared with web::Data, middleware-wrapped, error-handled with ResponseError, tested, and tuned for production.
  2. Choose a framework on purpose - actix-web for maximum performance, maturity, and batteries (websockets included), axum for the tower ecosystem and type-safe extractors, Rocket for concise macro-driven code. They've largely converged, so the mental model transfers.
  3. A database is the next layer, and Rust has no single default - sqlx (compile-checked raw SQL), SeaORM (async ORM), or Diesel (mature ORM). A sqlx::PgPool drops into the web::Data slot from Phase 4, so your handlers barely change.
  4. Lean on what's in the box - actix-web's websockets are a real strength when you need live updates.
  5. Tokio is the root - the async runtime driving every .await and every worker; learn it to remove the last of the magic.
  6. Build and finish one thing - carry the articles API to sqlx + Postgres, JWT auth, tracing, real config, and a deploy.

Quick check

Three decisions to take with you as you leave this guide:

[
  {
    "q": "You want maximum performance, a long production track record, and websockets already built in. Which framework fits on purpose?",
    "choices": [
      "Rocket, because it uses the most macros",
      "actix-web, the mature, batteries-included benchmark leader",
      "axum, because it's the newest",
      "None of them support websockets"
    ],
    "answer": 1,
    "explain": "actix-web is the mature, batteries-included heavyweight at or near the top of the benchmarks, with websockets in the box. Pick axum for the tower ecosystem, Rocket for concise macro-driven code."
  },
  {
    "q": "What is the real situation with ORMs in Rust for an actix-web API?",
    "choices": [
      "actix-web ships its own official ORM you must use",
      "There's no single default - sqlx (compile-checked raw SQL), SeaORM (async ORM), and Diesel (mature ORM) are the common choices",
      "Only Diesel works with async Rust",
      "Rust web apps can't use a database"
    ],
    "answer": 1,
    "explain": "Rust has no single default ORM. sqlx checks raw SQL at compile time, SeaORM is an async ORM on top of it, and Diesel is the mature, more sync-flavored ORM. You choose based on the job."
  },
  {
    "q": "You're swapping the in-memory store for sqlx + Postgres. Why do your handlers barely change?",
    "choices": [
      "Because actix-web rewrites handlers automatically when you add a database",
      "Because a sqlx::PgPool drops into the same web::Data slot from Phase 4, so handlers still extract it, query, and return a Responder",
      "Because you have to abandon web::Data and use globals instead",
      "They don't - every handler must be rewritten from scratch"
    ],
    "answer": 1,
    "explain": "Phase 4's web::Data pattern pays off: a PgPool goes into web::Data just like the in-memory store did. Handlers still extract the pool with web::Data<T>, run a query, and return a Responder - the bottom layer changes, the top stays."
  }
]

Before the quiz: without looking back, say (or jot down) the core idea of this phase in your own words.

Check your understanding 3 questions

1. You want maximum performance, a long production track record, and websockets already built in. Which framework fits on purpose?

2. What is the real situation with ORMs in Rust for an actix-web API?

3. You're swapping the in-memory store for sqlx + Postgres. Why do your handlers barely change?