Quickstart
Installation
This library’s only dependency is Starlette. It works with all Starlette-based frameworks, including FastAPI.
pip install starlette-context
Basic Usage
The context object is accessible when:
You’re within a request-response cycle
You’ve used either
ContextMiddlewareorRawContextMiddlewarein your ASGI app
Minimal Working Example
# app.py
from starlette.middleware import Middleware
from starlette.applications import Starlette
from starlette_context.middleware import ContextMiddleware
middleware = [Middleware(ContextMiddleware)]
app = Starlette(middleware=middleware)
# views.py
from starlette.requests import Request
from starlette.responses import JSONResponse
from starlette_context import context
from .app import app
@app.route("/")
async def index(request: Request):
# Access context data
context["user_id"] = "12345"
# Return context data in response
return JSONResponse(context.data)
Adding Plugins
Plugins automatically populate the context with useful information from request headers:
from starlette.middleware import Middleware
from starlette.applications import Starlette
from starlette_context import plugins
from starlette_context.middleware import ContextMiddleware
middleware = [
Middleware(
ContextMiddleware,
plugins=(
plugins.RequestIdPlugin(),
plugins.CorrelationIdPlugin()
)
)
]
app = Starlette(middleware=middleware)
With this setup, every request will have:
A request ID (generated if not provided in headers)
A correlation ID (generated if not provided in headers)
These values are accessible via context.data and are also included in the response headers.
Using with Logging
One of the main benefits of starlette-context is enriching your logs with request data:
import structlog
from starlette_context import context
def add_context(
logger, method_name, event_dict
):
"""Structlog processor that merges context data into every log entry."""
if context.exists():
event_dict.update(context.data)
return event_dict
structlog.configure(
processors=[
add_context,
structlog.dev.ConsoleRenderer(),
]
)
logger = structlog.get_logger()
@app.route("/")
async def index(request: Request):
logger.info("Processing request")
return JSONResponse({"message": "Hello World"})
The context.exists() guard is important — without it, any log emitted outside a request cycle (e.g. during startup) would raise ContextDoesNotExistError.
For a complete working example with JSON logging, see the Examples page.