5 min read
Django is too heavy when your real product is a JSON API, not a server-rendered monolith. If you spend more time fighting django-rest-framework over async, fighting channels to push 50k concurrent websockets, or watching cold starts on a Lambda chew through your budget, the framework is fighting you. FastAPI and Litestar are the two serious replacements for that specific job, and the decision between them is not about taste. It is about how you ship, deploy, and operate.
Django is not slow. It is heavy. A fresh django-admin startproject pulls in 70+ packages, the ORM, the admin, the auth, the template engine, sessions, messages, and the contenttypes framework. django-admin --version 5.1 still ships a settings module designed for 2009. None of that matters if you are running bbc.co.uk style content with a Postgres backend and Gunicorn workers. It matters a lot if you are shipping the kind of work the HMRC and Monzo backends actually do: stateless JSON over HTTP, talking to Postgres or DynamoDB, behind an async gateway.
The real cost shows up at the edges. Cold start on a Django Lambda is 800ms-1.2s on a decent image. A FastAPI app on the same Lambda is 120-180ms. Container size: a Django 5 + DRF image is ~180MB compressed. A FastAPI image is ~45MB. If you run thousands of ephemeral workers (which UK fintech and adtech teams do), that is not a vanity metric, it is the difference between a bill your finance team signs and a Slack message from your VP asking why AWS cost jumped.
If your service has one job (accept JSON, validate it, write to a database, return JSON) the ORM is dead weight. SQLAlchemy 2.0 with async_session is faster, more explicit, and plays well with both FastAPI and Litestar. The admin is not used by any service that does not have human operators. Templates are not used by anything returning application/json. You are paying 90MB of container and a chunk of import time for features your service never calls.
FastAPI wins here for raw ecosystem. Pydantic v2 is genuinely excellent, and the OpenAPI generation saves hours on NHS Digital style integration work. Litestar is the leaner choice if you want fewer dependencies and a smaller surface area. It uses msgspec or Pydantic, has its own dependency injection, and ships with an OpenAPI generator that is good enough without being magical.
from litestar import Litestar, get
from litestar.dto import DTOData
from msgspec import Struct
class Health(Struct):
status: str
db: bool
@get("/health", sync_to_thread=False)
def health() -> Health:
return Health(status="ok", db=True)
app = Litestar([health])
That is the whole app. One import surface, no settings module, no app factory, no INSTALLED_APPS. For a microservice that is exactly the right shape.
Django added async views in 3.1 and has been catching up ever since. async def views, async_orm in 4.1, channels for websockets. The problem is the ecosystem is still sync-first. DRF is sync. Most third-party packages assume sync. The moment you try to call requests.get inside an async view you either deadlock the worker or wrap it in sync_to_async and lose half the benefit.
FastAPI was async from day one. Litestar was async from day one. Your async def endpoint actually runs on the event loop, calls httpx, asyncpg, or aioboto3 directly, and you do not have to think about thread pools. For a service that fans out to three downstream APIs (which is most UK fintech backends), the throughput delta is 3x-5x per worker on the same hardware.
If you write more serializers than models, you have a FastAPI-shaped problem. Pydantic v2 is written in Rust, validates nested JSON at ~5x the speed of DRF serializers, and gives you generated TypeScript clients for free if you hand the OpenAPI schema to a frontend team. Litestar's @dataclass + DTO pattern is similar but with less magic and fewer dependencies.
DRF is the right tool when you have a relational model, many endpoints, browsable API users, and a team that already knows it. The moment you find yourself writing a custom Serializer with five nested SerializerMethodField calls just to validate a webhook payload from Stripe, switch. pydantic.BaseModel with a couple of field_validator decorators is faster to write and faster to run.
FastAPI and Litestar were designed for the Gunicorn-of-the-future: Uvicorn behind a reverse proxy, or any of the new Rust servers (Granian, Robyn). Cold start matters. Memory matters. A Django monolith running on a single VM at example.co.uk for ten years is a different beast to a stateless API that gets scaled to zero at night.
There is also a hiring angle. The pool of UK devs who can write a clean FastAPI service with proper lifespan handling, dependency overrides for tests, and structured logging is small but growing fast. The pool of devs who know Django deeply is larger and older. Pick based on what your team can maintain, not what looks good on a blog post.
FastAPI if you want ecosystem, hiring pool, and Pydantic v2 maturity. Use it for anything NHS Digital, GOV.UK, or HMRC-facing where you need OpenAPI compliance and battle-tested middleware. The dependency injection is simpler than Litestar's, the docs are better, and fastapi-users exists if you need auth out of the box.
Litestar if you want fewer dependencies, msgspec performance, and a framework that does not change its DI shape every minor version. It is younger, the ecosystem is smaller, and you will write more of your own middleware. But the core is solid, the OpenAPI generation is good, and the import graph is half the size. For greenfield services where you control everything and want to ship in two weeks, Litestar is the better bet. For anything with existing FastAPI code or where you need to hire fast, FastAPI.
It depends on what you measure. For a server-rendered app with an admin, no. For a stateless JSON API that needs to be async, scale to zero, and start cold in under 200ms, yes. The weight is in the unused features, not the runtime cost per request.
You can, but it is pointless. SQLAlchemy 2.0 async is a better fit. If you really need the Django ORM (for migrations, admin, auth), keep Django and accept the weight. If you do not need those, drop Django entirely.
Starlette is the ASGI toolkit FastAPI is built on. Using Starlette directly means writing your own routing, validation, and OpenAPI generation. FastAPI and Litestar are the right level of abstraction for production. Starlette is a building block, not a framework choice.