★ 99,104PythonMITupdated Jun 2026
best for typed, async JSON APIs with automatic interactive docs
FastAPI is the default for new Python APIs for a real reason: declare one Pydantic model and you get request validation, response serialization, and accurate OpenAPI docs that stay in sync by construction. The dependency injection system is better thought out than anything Flask offers, and it's fast enough that "Python is slow" stopped being an honest objection for most web workloads.
But FastAPI is barely a framework of its own — it's Starlette and Pydantic with good naming, and the first non-trivial thing you hit sends you into Starlette's docs instead of FastAPI's. The sharper problem is the async footgun: one blocking call inside an async route stalls the whole event loop, silently, with nothing in the logs pointing at why. Background tasks have no retry and no persistence, so real async work means bolting on Celery or ARQ from day one.
Compare it to Litestar, which makes the same pitch — typed, async, automatic docs — with faster validation and more structure built in. FastAPI wins on ecosystem size and the fact that every Stack Overflow answer already exists; that's still worth more than Litestar's extra polish for most teams.
Our full take →GitHub ↗
★ 87,819PythonBSD-3-Clauseupdated Jun 2026
best for full-stack apps that want ORM, admin, and auth included from day one
Django is still the right default for anything that's a full app and not just an API. The ORM, migrations, admin panel, and auth system have survived twenty years of production load, and the admin alone — a usable back-office generated from your models with almost no code — is worth more than most single features on this list.
The catch is that Django made its big decisions before async existed. The ORM is still sync-only, so an "async view" that touches the database is either secretly blocking or wrapped in sync_to_async, which gives up most of the reason you went async in the first place. It's also a lot of framework for a pure JSON API — if you're not using the admin, templates, or most of the ORM's surface, FastAPI or Starlette let you skip that weight entirely.
Where Django wins over everything else here is the parts other frameworks make you assemble by hand: auth, admin, migrations, security defaults. Where it loses is async — Tornado and Robyn were built around concurrency from day one; Django bolted it on later and it still shows in the ORM.
Our full take →GitHub ↗
★ 74,931PythonBSD-3-Clauseupdated Oct 2026
best for small apps and prototypes where you want minimal structure and full control
Flask's whole pitch is having no opinions, and for a small app or a prototype that's genuinely the right amount of framework. You can read app.py and blueprints.py in an afternoon and understand the entire request lifecycle, and the extension ecosystem means you're rarely the first person to hit a given problem.
The honest cost of "no opinions" is that any app past toy size ends up inventing its own version of the structure Django gives by default, and that structure differs project to project. There's no ORM, no validation, no admin — a real Flask app is Flask plus four or five extensions whose version compatibility is now your problem. It's also still WSGI underneath: async syntax works, but you don't get real concurrency without switching to Quart or fronting it with gevent workers.
Next to FastAPI, Flask has no validation story at all — fine if you want that control yourself, a real gap if you expect anything close to automatic docs and schema generation out of the box.
Our full take →GitHub ↗
★ 8,523PythonMITupdated Oct 2026
best for teams who want FastAPI-like ergonomics with stricter architecture and built-in dependency injection
Litestar is what FastAPI might look like if the architecture had been designed before the README was written. msgspec validation is genuinely faster than Pydantic on the hot path, class-based controllers with layered dependency injection give more structure than Starlette, and the built-in SQLAlchemy integration answers the ORM question FastAPI just doesn't.
The tradeoff is maturity, not design. The ecosystem is a fraction of FastAPI's size, so the first edge case you hit has no waiting Stack Overflow answer, and the docs' example gallery is doing more work than it should. Supporting Pydantic v1, v2, msgspec, and attrs simultaneously is a real feature, but it also means your error messages look different depending on which library happened to validate your model — a strange thing to debug at 2am. It's also a small core team, which is a bus-factor question worth asking before betting years of production infrastructure on it.
Pick Litestar over FastAPI if you want the extra structure and speed and can live with a smaller ecosystem; pick FastAPI if you'd rather have the thing everyone else is already using.
Our full take →GitHub ↗
★ 12,676PythonBSD-3-Clauseupdated Oct 2026
best for building your own framework on a minimal, unopinionated ASGI core
Starlette is what you reach for when you don't want a framework, you want primitives — routing, requests, responses, middleware, each importable on its own, with anyio as the only hard dependency. It's also, not incidentally, what FastAPI is built on, so it's handled real production traffic for years before you ever touch it.
What you give up is everything FastAPI adds on top: no dependency injection, no request validation, no automatic docs. Fine if you know that going in and you're building your own thing on it; a bad surprise if you picked Starlette expecting FastAPI-lite. BaseHTTPMiddleware has real footguns around streaming responses that aren't obvious until you hit them, and the error messages are thin enough that you'll read Starlette's source more often than Flask's docs.
If FastAPI is Starlette with the convenient parts filled in, Starlette is for people who'd rather fill those parts in themselves — or who are building the next FastAPI.
Our full take →GitHub ↗
★ 22,164PythonApache-2.0updated Oct 2026
best for long-lived connections and websockets at real scale
Tornado was handling thousands of concurrent long-lived connections — long polling, WebSockets — before asyncio existed, and that heritage still matters if you need a server holding open a lot of sockets without a process per connection. The IOLoop and coroutine primitives are battle-tested, not just documented.
The problem is that the rest of the Python async world moved to asyncio and ASGI, and Tornado didn't come with it — it wraps asyncio now but keeps its own RequestHandler and Application APIs, so it doesn't plug into Starlette, uvicorn, or any ASGI tooling. New middleware, tutorials, and answers skew old because nobody's building fresh things on Tornado in 2026. You're also writing request validation and routing by hand — no OpenAPI generation, no typed models, which every framework here except Flask gives you.
Pick Tornado only if you specifically need its long-connection model and don't mind living outside the ASGI ecosystem everything else converged on. For a typical API, Robyn or FastAPI get you async without that isolation.
Our full take →GitHub ↗
★ 9,126PythonMITupdated Jul 2026
best for bolting a fast, typed API layer onto an existing Django app instead of adopting DRF
If you already run Django and rewriting in FastAPI is a non-starter, Django Ninja is the pragmatic answer — FastAPI-style decorators and automatic docs on top of the ORM you already have, with create_schema turning Django models into Pydantic schemas instead of you maintaining two versions of the same shape by hand.
The gap shows up at scale. Class-based views, which is how most real Django code is organized, are still just a proposal, so Ninja routes in a large app tend to become flat functions instead of the organized views Django developers expect. create_schema is convenient for simple models and a fight once you're into complex relations or custom field types. And "async-ready" is only as true as Django's own async ORM, which still can't do everything the sync ORM does — so you inherit Django's async gap along with everything else.
Think of it as the compromise between Django and FastAPI: less rewrite than adopting FastAPI outright, but still bound by what Django's ORM can and can't do asynchronously.
Our full take →GitHub ↗
★ 7,410PythonBSD-2-Clauseupdated Oct 2026
best for squeezing out raw request throughput via a Rust-backed runtime
Robyn's bet is that Python's web frameworks are still bottlenecked by Python itself, so it moved routing and dispatch into a Rust core and kept a Flask-style decorator API on top. The result is real: sync and async handlers on the same app with no adapter layer, multi-process scaling as a CLI flag instead of a gunicorn config, and a CI pipeline that actually tracks performance regressions instead of a one-time benchmark screenshot.
What you're taking on is a pre-1.0 project with no visible semver policy, so breaking changes between minor versions are a real possibility, not a hypothetical. The feature list has also started growing sideways — an MCP server and "AI Agent" routing bolted onto a project whose actual case for existing is raw throughput — which reads more like chasing attention than hardening the routing and middleware core. When something breaks in the Rust layer, the Python traceback stops at the boundary; building from source needs Rust and maturin, a real tax if your platform doesn't have a prebuilt wheel.
It's the fastest thing on this list by design, and the only one where "will this still be maintained the way you need in two years" is a genuinely open question — Tornado at least has a decade of stability behind its niche.
Our full take →GitHub ↗
// questions people ask
Before you choose
Should I use FastAPI or Django for a new project?
FastAPI if you're building a JSON API with no admin panel or server-rendered pages — the typed, async-first design is built for exactly that. Django if you need an ORM, auth, and an admin interface out of the box; its ORM is sync-only, which costs you something in a pure API, but for a full-stack app it saves months.
What's actually different between FastAPI, Litestar, and Starlette?
Starlette is the minimal ASGI core FastAPI is built on — primitives with no validation or DI layered in. FastAPI adds Pydantic validation, dependency injection, and automatic docs on top of it. Litestar does the same job as FastAPI but with faster msgspec validation and more built-in structure, at the cost of a much smaller ecosystem.
Is Flask still worth learning in 2026?
Yes, for small apps, prototypes, and anyone who wants to understand request handling without a framework making decisions for them. For anything that needs validation, an ORM, or real async concurrency, you'll end up assembling extensions that Django or FastAPI give you for free.
When do Tornado or Robyn make more sense than the others?
Tornado if you specifically need thousands of long-lived connections — WebSockets, long polling — and can live outside the ASGI ecosystem everything else has converged on. Robyn if raw request throughput matters more than ecosystem maturity, since it's still pre-1.0 with no semver guarantees.
Pick based on the shape of what you're building, not the one with the shortest list of complaints — every framework here has a real one. If you want more comparisons like this without doing the digging yourself, the weekly finds.dev email runs the same kind of read on whatever you're building next.