fastapi/fastapi
Middleware
Purpose
fastapi/middleware/ is a thin layer over Starlette's middleware ecosystem plus one piece of original code. It exists so user code can write from fastapi.middleware.cors import CORSMiddleware rather than reaching into Starlette directly.
Directory layout
fastapi/middleware/
├── __init__.py # empty
├── asyncexitstack.py # AsyncExitStackMiddleware (the only original code here)
├── cors.py # re-export of starlette.middleware.cors
├── gzip.py # re-export of starlette.middleware.gzip
├── httpsredirect.py # re-export of starlette.middleware.httpsredirect
├── trustedhost.py # re-export of starlette.middleware.trustedhost
└── wsgi.py # re-export of starlette.middleware.wsgiEach re-export module is a single line:
from starlette.middleware.cors import CORSMiddleware as CORSMiddleware # noqaAsyncExitStackMiddleware
The only piece of FastAPI-original middleware. From fastapi/middleware/asyncexitstack.py:
class AsyncExitStackMiddleware:
def __init__(self, app, context_name="fastapi_middleware_astack"):
self.app = app
self.context_name = context_name
async def __call__(self, scope, receive, send):
async with AsyncExitStack() as stack:
scope[self.context_name] = stack
await self.app(scope, receive, send)The middleware creates an outer AsyncExitStack per request and stores it on the ASGI scope under fastapi_middleware_astack. Anything that needs to clean up after the response is fully sent (e.g. UploadFile.close()) registers itself on this stack. The framework adds it as the outermost FastAPI-owned middleware in FastAPI.__init__, so user middleware sits inside it.
The two inner stacks (fastapi_inner_astack, fastapi_function_astack) are created in request_response() in fastapi/routing.py — they own dependency cleanup (Depends(...) callables that yield) and run before the outer middleware unwinds.
Adding middleware
User code uses Starlette's app.add_middleware(...):
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
app = FastAPI()
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)add_middleware is inherited from Starlette. The middleware stack is built lazily on first request (Starlette's behaviour), so middlewares can be added at any point during configuration.
Integration points
- Up to user code — re-export modules are the documented import paths.
- Down to Starlette — every implementation except
AsyncExitStackMiddlewarelives in Starlette. - Cross to dependency cleanup —
AsyncExitStackMiddlewarecooperates with the per-request stacks set up infastapi/routing.py.
Entry points for modification
- New middleware re-export: copy
cors.py, change the import. Keep theas Namerebinding so ruff does not strip it as unused. - New original middleware: add a class to
fastapi/middleware/mirroringAsyncExitStackMiddleware. If it should be installed by default, register it inFastAPI.__init__.
See Routing for how the per-request AsyncExitStacks drive dependency cleanup.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.
Previous
Exceptions
Next
Pydantic compatibility