FastAPI is the framework that brought type-driven API development to Python. In 2026, FastAPI 0.115 running on Python 3.12+ with Pydantic v2 and asyncpg is the standard async Python API stack — delivering JSON validation 5–50× faster than Pydantic v1 and request throughput that rivals Go for I/O-bound workloads. The framework is intentionally thin: it handles routing, validation, serialisation, and documentation. You bring the ORM, the auth, and the business logic.
What changed in 2026
- FastAPI 0.115 + Pydantic v2 by default. Pydantic v2 (written in Rust) validates models 5–50× faster than v1. Field declarations use
Annotated types throughout.
- Python 3.12 is the minimum recommended.
match statements, @override decorator, improved asyncio task groups (asyncio.TaskGroup), and faster startup.
lifespan replaced startup/shutdown events. The @app.on_event decorator is deprecated; use the lifespan context manager.
- Structured concurrency.
asyncio.TaskGroup is the 2026 pattern for concurrent async operations inside a request handler.
Project setup
python -m venv .venv && source .venv/bin/activate
pip install "fastapi[standard]>=0.115" sqlalchemy[asyncio] asyncpg alembic
uvicorn main:app --reload
fastapi[standard] installs uvicorn, python-multipart, and email-validator automatically.
The minimal app
from contextlib import asynccontextmanager
from fastapi import FastAPI
@asynccontextmanager
async def lifespan(app: FastAPI):
# Startup: connect DB pool, warm caches
print("starting up")
yield
# Shutdown: close connections
print("shutting down")
app = FastAPI(lifespan=lifespan)
@app.get("/health")
async def health() -> dict[str, str]:
return {"status": "ok"}
Open http://localhost:8000/docs — interactive OpenAPI UI is there by default.
Pydantic v2 models
from pydantic import BaseModel, Field, model_validator
from datetime import datetime
from typing import Annotated
PostTitle = Annotated[str, Field(min_length=1, max_length=300)]
class PostCreate(BaseModel):
title: PostTitle
body: str
published: bool = False
class PostResponse(BaseModel):
id: int
title: str
created_at: datetime
model_config = {"from_attributes": True} # replaces orm_mode=True
from_attributes = True allows FastAPI to serialise SQLAlchemy model instances directly into the response schema.
Dependency injection pattern
from fastapi import Depends, HTTPException, status
from sqlalchemy.ext.asyncio import AsyncSession
async def get_db() -> AsyncSession:
async with async_session_maker() as session:
yield session
async def get_current_user(
token: str = Depends(oauth2_scheme),
db: AsyncSession = Depends(get_db),
) -> User:
user = await verify_token_and_fetch_user(token, db)
if not user:
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED)
return user
@app.get("/me", response_model=UserResponse)
async def me(user: User = Depends(get_current_user)) -> UserResponse:
return user
The DI system handles teardown automatically — the get_db generator closes the session after the request completes.
Async SQLAlchemy 2.0 setup
from sqlalchemy.ext.asyncio import create_async_engine, async_sessionmaker
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
engine = create_async_engine("postgresql+asyncpg://user:pass@localhost/db")
async_session_maker = async_sessionmaker(engine, expire_on_commit=False)
class Base(DeclarativeBase):
pass
class Post(Base):
__tablename__ = "posts"
id: Mapped[int] = mapped_column(primary_key=True)
title: Mapped[str] = mapped_column()
published: Mapped[bool] = mapped_column(default=False)
Mapped with type annotations replaces the old Column(Integer, ...) API — cleaner and type-safe.
FastAPI vs Django comparison
| Factor |
FastAPI |
Django |
| Async support |
Full, first-class |
Partial (ORM in 5.1) |
| Validation |
Pydantic v2 (fast) |
DRF Serialisers |
| ORM |
SQLAlchemy (bring own) |
Built-in ORM |
| Admin UI |
None (bring own) |
Excellent built-in |
| Auth, sessions |
Bring your own |
Built-in |
| OpenAPI docs |
Auto-generated |
Manual or drf-spectacular |
| Best for |
APIs, microservices |
Full web apps |
Common mistakes
Using synchronous functions in an async app. Calling a blocking function (e.g., requests.get, time.sleep) inside an async def route blocks the entire event loop. Use httpx.AsyncClient and asyncio.sleep instead.
No connection pool limits. create_async_engine(pool_size=5, max_overflow=10) limits concurrent DB connections. Without it, under load you exhaust the Postgres connection limit.
Returning SQLAlchemy models directly. Lazy-loaded relationships raise MissingGreenlet in async context. Always use response_model and ensure relationships are eagerly loaded.
Not versioning your API. Use an APIRouter with prefix /v1/ from the start. Retrofitting versioning after clients depend on your routes is painful.
What to skip
Flask-RESTful patterns in FastAPI. FastAPI is not Flask. Resource-class patterns do not fit — use plain async def route functions.
asyncio.gather() without error handling. If one task in a gather() fails and you do not handle the exception, other tasks may be cancelled silently. Use asyncio.TaskGroup for structured concurrency.
- Starlette middleware for everything. Middleware runs on every request. For per-route logic (auth, rate limiting), use
Depends() instead.
FAQ
FastAPI vs Django in 2026?
FastAPI for pure API services, microservices, and ML model serving. Django for full-stack web applications that need admin, auth, and sessions out of the box. See FastAPI vs Flask in 2026.
Is FastAPI production-ready?
Yes. Netflix, Uber (internal services), and many startups run FastAPI at scale. Uvicorn + Gunicorn with multiple workers is the production deployment pattern.
How do I run background tasks?
BackgroundTasks in FastAPI handles fire-and-forget tasks. For reliable job queuing, use Celery + Redis or ARQ (async Redis queue).
What is the recommended auth setup?
fastapi-users gives you registration, login, JWT, and OAuth2 with a few lines. For custom needs, python-jose for JWT and passlib[bcrypt] for password hashing.
Where to go next
Pair FastAPI with how to set up a database in 2026 for PostgreSQL setup, compare it with how to learn Django in 2026 to choose the right tool, and explore how to containerize an app in 2026 for production deployment.