Why FastAPI for Python APIs
Type hints become validation and documentation, async is not an afterthought, and Pydantic keeps one definition of your data. Why I reach for FastAPI.
- python
- fastapi
- api
Most Python APIs are built by writing validation code, then writing it again when the data shape changes, then documenting the API by hand and letting the documentation go out of date. FastAPI exists because that sequence is unnecessary.
I reach for it on most new APIs I build, and this is why.
One definition of your data
You declare a model, and everything downstream is derived from that single declaration:
from pydantic import BaseModel, EmailStr
class CustomerCreate(BaseModel):
name: str
email: EmailStr
monthly_limit: int = 100
That one class gives you request parsing, type coercion, field validation, an OpenAPI schema, and the documentation example. When you add a field, all five update together.
The failure mode this eliminates is the one I have seen repeatedly in long-lived codebases: a validation rule implemented in the serializer, a different one in the view, and a third described in the API documentation that matches neither. Three definitions of the truth, drifting apart over eighteen months.
Pydantic will not do your business logic. That is fine — it is not trying to. It holds the shape of the data, and the shape of the data is the part that gets duplicated.
Validation at the boundary
Malformed input gets rejected before it reaches your logic. Not after you have created a partial record, discovered the field was missing, and started a compensation transaction.
For a developer who has spent years handling data that came from integrations with other people’s systems, this is the benefit I care about most. Most of what looks like a business logic bug in an API is actually an input shape problem that was allowed in too far.
Async without the rewrite
FastAPI treats async as the default rather than an optimisation you retrofit. When a request needs data from four services — a payment provider, a CRM, a notification system, an internal database — those calls happen concurrently by default.
The practical effect on integration-heavy backends is large. An endpoint that calls six external APIs sequentially spends most of its life waiting on the network. Concurrency turns that wait into a single round trip.
Generated documentation that stays correct
The OpenAPI schema is a by-product of the code, which means it cannot drift. This sounds like a small thing. It is not.
The first time a frontend developer or a partner company builds against your generated docs instead of your Slack messages, the integration conversation becomes technical instead of archaeological. This is a bigger lever on delivery speed than most framework choices.
Where it is the wrong choice
I would not choose FastAPI when:
- You need a full application with an admin interface. Django gives you one for free. Rebuilding it is weeks of work for something that already exists.
- You want a deep ecosystem of battle-tested add-ons. Celery, Django admin, Django REST Framework and the wider Django package index give you a large body of solved problems to lean on. FastAPI’s ecosystem is growing fast, but it is younger and thinner.
- You need a frontend in the same project. Django ships with templates, forms and a user system, so a full product is mostly configuration. Pair FastAPI with React, Vue or another frontend framework and you are running two projects, two build pipelines and an explicit API client layer between them — which is fine, but it is real boilerplate Django does not ask you to write.
- You want migrations, auth and admin batteries included. Django includes them; FastAPI makes each an explicit choice.
That last point is the honest framing. FastAPI is a smaller, sharper tool. For an API — and especially an API that is consumed by other software — smaller and sharper is usually right.
The thing that surprised me
The chatbot that answers questions about Romanian fiscal legislation is built in Django. It has users, models, an admin and background jobs, so Django was the right call and I would build it the same way again.
What the project did teach me is how much of what I like about FastAPI is not really FastAPI. Having the schema generated from the code, so I could change the retrieval layer’s output shape and see immediately what broke, is a property of Pydantic, not of the framework. Django Ninja gives me the same thing inside Django. What FastAPI removes is the layer around it — the wiring, the conventions, the structure you get for free and would spend a week reproducing.
That feedback loop is the actual reason I prefer this framework, and it is not something the feature comparison lists mention.
If you are building an API and want a straight opinion on the stack, send me a message. I am happy to tell you when Django is the better answer too.
Found a process worth automating?
Tell us about it. One email, no forms, no sales sequence.