FastAPI vs Django vs Flask
Python has three major web frameworks: Django (batteries included), Flask (minimalist), and now FastAPI (modern async). Each has its place.
The Quick Summary
| Feature | Django | Flask | FastAPI |
|---|---|---|---|
| Philosophy | Batteries included | Minimal | Modern async |
| Learning curve | Steeper | Easy | Easy |
| Performance | Good | Good | Excellent |
| Async support | Improving | Limited | Native |
| Admin | Built-in | Add-on | None |
| ORM | Built-in | Add-on | None |
| API docs | DRF add-on | Add-on | Built-in |
| Type hints | Optional | Optional | Required |
FastAPI: The New Kid
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class User(BaseModel):
name: str
email: str
@app.get("/users/{user_id}")
async def get_user(user_id: int) -> User:
return User(name="Alice", email="alice@example.com")
@app.post("/users/")
async def create_user(user: User) -> User:
return user
Run with: uvicorn main:app --reload
Standout features:
- Automatic OpenAPI docs at
/docs - Pydantic for validation
- Async by default
- Type hints drive the API
Django: The Full Package
# models.py
from django.db import models
class User(models.Model):
name = models.CharField(max_length=100)
email = models.EmailField()
# views.py
from rest_framework import viewsets
from .models import User
from .serializers import UserSerializer
class UserViewSet(viewsets.ModelViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer
# urls.py
from rest_framework.routers import DefaultRouter
router = DefaultRouter()
router.register('users', UserViewSet)
Standout features:
- Admin panel for free
- ORM with migrations
- Authentication built-in
- Massive ecosystem
Flask: The Minimalist
from flask import Flask, jsonify, request
app = Flask(__name__)
users = {}
@app.route('/users/<int:user_id>')
def get_user(user_id):
return jsonify(users.get(user_id, {}))
@app.route('/users/', methods=['POST'])
def create_user():
data = request.get_json()
users[len(users)] = data
return jsonify(data), 201
Standout features:
- Learn in an afternoon
- Choose your own components
- Excellent for microservices
- No magic
Performance Comparison
Benchmarks vary, but the pattern is consistent:
| Framework | Requests/sec (relative) |
|---|---|
| FastAPI | 100% |
| Flask + Gunicorn | 40-60% |
| Django + Gunicorn | 30-50% |
FastAPI’s ASGI + async gives it a real edge for I/O-bound workloads.
When to Choose Each
Choose Django When
- Building a full web application (not just API)
- Need admin interface
- Want ORM with migrations
- Security is critical (built-in protections)
- Team knows Django
# Django gives you this for free
# - User authentication
# - Admin panel
# - CSRF protection
# - ORM + migrations
# - Template engine
Choose Flask When
- Building microservices
- Learning web development
- Need maximum flexibility
- Simple API with custom components
- Existing Flask codebase
# Flask: add what you need
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager
from flask_marshmallow import Marshmallow
Choose FastAPI When
- Building pure APIs
- Performance matters
- Team knows type hints
- Want auto-generated docs
- Async is important
# FastAPI: types drive everything
from fastapi import FastAPI, Query
@app.get("/items/")
async def list_items(
skip: int = Query(default=0, ge=0),
limit: int = Query(default=10, le=100)
):
return items[skip : skip + limit]
Hybrid Approaches
FastAPI with SQL
from fastapi import FastAPI, Depends
from sqlalchemy.orm import Session
from . import models, database
app = FastAPI()
def get_db():
db = database.SessionLocal()
try:
yield db
finally:
db.close()
@app.get("/users/{user_id}")
def get_user(user_id: int, db: Session = Depends(get_db)):
return db.query(models.User).filter(models.User.id == user_id).first()
Django Ninja
FastAPI-style APIs in Django:
from ninja import NinjaAPI
from .models import User
api = NinjaAPI()
@api.get("/users/{user_id}")
def get_user(request, user_id: int):
return User.objects.get(id=user_id)
Best of both: Django’s ORM + FastAPI’s ergonomics.
Migration Considerations
Flask → FastAPI
Relatively straightforward:
- Route decorators are similar
- Add type hints
- Switch to async where beneficial
- Replace validation with Pydantic
Django → FastAPI
Harder:
- Lose the ORM (or use SQLAlchemy)
- Lose the admin
- Lose the ecosystem
- Only worth it for API-only projects
My Recommendations
Starting a new project?
- Full web app: Django
- Pure API: FastAPI
- Learning: Flask
Existing project?
- Stay with what you have
- Django Ninja for Django + FastAPI benefits
Microservices?
- FastAPI or Flask
- Django is overkill
Final Thoughts
There’s no “best” framework. Django, Flask, and FastAPI solve different problems.
Django: “I don’t want to think about components” Flask: “I want to choose my own adventure” FastAPI: “I want modern async with type safety”
Choose based on your project needs, team skills, and personal preference. They’re all production-ready.
The best framework is the one that ships your product.