
Introduction
Modern Python API development has converged on two frameworks that share the same foundation — Pydantic validation, automatic OpenAPI documentation, and type-safe request handling — but diverge sharply in architecture and ecosystem fit. FastAPI is a standalone, async-first ASGI framework built for greenfield services and maximum performance. Django Ninja is a FastAPI-inspired API layer that integrates directly into Django, preserving every investment in the ORM, admin, auth, and middleware.
The right choice is not about which framework is superior — it is about which framework eliminates friction for your specific stack. FastAPI unlocks maximum async performance and architectural freedom. Django Ninja unlocks type-safe APIs with zero migration cost for teams already operating in the Django ecosystem. Both generate production-grade OpenAPI documentation automatically and validate requests through Pydantic v2.
FastAPI
FastAPI is a standalone ASGI framework built on Starlette and Pydantic.
pip install fastapi uvicorn
Basic Example
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
price: float
description: str = None
@app.get("/")
def root():
return {"status": "ok"}
@app.post("/items/")
def create_item(item: Item):
return item
@app.get("/items/{item_id}")
def read_item(item_id: int, q: str = None):
return {"item_id": item_id, "q": q}
uvicorn main:app --reload
# Docs at http://localhost:8000/docs
Async Support
import httpx
from fastapi import FastAPI
app = FastAPI()
@app.get("/external-data/")
async def get_external():
async with httpx.AsyncClient() as client:
r = await client.get("https://api.example.com/data")
return r.json()
Dependencies
from fastapi import Depends, HTTPException
from fastapi.security import OAuth2PasswordBearer
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
def get_current_user(token: str = Depends(oauth2_scheme)):
user = decode_token(token)
if not user:
raise HTTPException(status_code=401)
return user
@app.get("/me/")
def read_me(user = Depends(get_current_user)):
return user
Django Ninja
Django Ninja adds a FastAPI-style API layer on top of Django — you keep the ORM, auth, admin, and middleware.
pip install django-ninja
Basic Example
# api.py
from ninja import NinjaAPI, Schema
api = NinjaAPI()
class ItemSchema(Schema):
name: str
price: float
@api.get("/items/{item_id}")
def get_item(request, item_id: int):
return {"item_id": item_id}
@api.post("/items/")
def create_item(request, item: ItemSchema):
return item
# urls.py
from django.urls import path
from .api import api
urlpatterns = [
path("api/", api.urls),
]
Using Django ORM Directly
from ninja import NinjaAPI, Schema
from myapp.models import Post
api = NinjaAPI()
class PostOut(Schema):
id: int
title: str
content: str
@api.get("/posts/", response=list[PostOut])
def list_posts(request):
return Post.objects.filter(status="published")
@api.get("/posts/{post_id}", response=PostOut)
def get_post(request, post_id: int):
return get_object_or_404(Post, id=post_id)
Django Auth Integration
from ninja import NinjaAPI
from ninja.security import django_auth
api = NinjaAPI(auth=django_auth)
@api.get("/profile/")
def profile(request):
return {"username": request.user.username}
Async in Django Ninja
@api.get("/async-posts/")
async def async_posts(request):
posts = await Post.objects.filter(status="published").aall()
return posts
Side-by-Side Comparison
The table below captures the decisive differences across the dimensions that determine framework fit for real production systems:
| Feature | FastAPI | Django Ninja |
|---|---|---|
| Base framework | Starlette (ASGI) | Django |
| ORM | SQLAlchemy / Tortoise | Django ORM ✅ |
| Auth | Custom / OAuth2 | Django auth ✅ |
| Admin panel | ❌ | Django admin ✅ |
| Async | Native | Via Django async |
| OpenAPI docs | ✅ Auto | ✅ Auto |
| Pydantic | ✅ v2 | ✅ v2 |
| Middleware | Starlette | Django ✅ |
| Learning curve | Low | Low (if Django known) |
| Migrations | Alembic / manual | Django migrations ✅ |
| WebSockets | ✅ | ✅ |
| Testing | pytest + httpx | Django test client |
Code Comparison: Same Endpoint
FastAPI:
from fastapi import FastAPI, HTTPException, Depends
from pydantic import BaseModel
from sqlalchemy.orm import Session
app = FastAPI()
class UserOut(BaseModel):
id: int
name: str
email: str
@app.get("/users/{user_id}", response_model=UserOut)
def get_user(user_id: int, db: Session = Depends(get_db)):
user = db.query(User).filter(User.id == user_id).first()
if not user:
raise HTTPException(status_code=404, detail="Not found")
return user
Django Ninja:
from ninja import NinjaAPI, Schema
from django.shortcuts import get_object_or_404
from myapp.models import User
api = NinjaAPI()
class UserOut(Schema):
id: int
name: str
email: str
@api.get("/users/{user_id}", response=UserOut)
def get_user(request, user_id: int):
return get_object_or_404(User, id=user_id)
Django Ninja is noticeably less boilerplate when you already have Django models.
When to Choose FastAPI
- Greenfield project with no Django dependency
- Need maximum async performance
- Building a standalone microservice
- Team prefers SQLAlchemy or Tortoise ORM
- Want full control over the stack
When to Choose Django Ninja
- Already have a Django project
- Want to add an API alongside existing views
- Need Django ORM, admin, and auth out of the box
- Migrating from DRF to a type-safe API layer
- Want minimal new dependencies
Conclusion
Both frameworks are production-ready and actively maintained. FastAPI wins on raw async performance, architectural flexibility, and ecosystem breadth — it is the right choice for greenfield microservices and teams that want full control over their stack. Django Ninja wins when you are already in the Django ecosystem: it delivers type-safe, auto-documented APIs with zero friction against existing models, auth, and admin, transforming a Django project into a modern API platform without a rewrite.
The decision is not about which framework is better. It is about which framework eliminates the most friction for your team’s specific context.
👉 Read more on Medium
References
- FastAPI Documentation - Official docs
- Django Ninja GitHub - Source code
- Pydantic - Data validation used by both