Published on Nov. 19, 2025
Go homeSimple Server Timing in Django
Server Timing
This middleware attaches a timings object to a request which can be used to add server timings to the response headers.
import collections
import contextlib
import time
from django.http import HttpRequest, HttpResponse
from django.utils.deprecation import MiddlewareMixin
class Timings(collections.UserList[str]):
@contextlib.contextmanager
def timeit(self, name: str) -> t.Iterator[None]:
start = time.monotonic_ns()
yield
dur_ns = time.monotonic_ns() - start
dur = dur_ns / 1_000_000
self.data.append(f"{name};dur={dur}")
def serialize(self) -> str:
return ",".join(self.data)
class ServerTimingMiddleware(MiddlewareMixin):
"""Adds server timing headers to the response."""
def process_request(self, request: HttpRequest) -> None:
request._timings_total_start = time.monotonic_ns() # type:ignore
request.timings = Timings() # type:ignore
def process_response(self, request: HttpRequest, response: HttpResponse) -> HttpResponse:
if not hasattr(request, "timings"):
return response
timings = request.timings # type:ignore
dur_ns = time.monotonic_ns() - request._timings_total_start # type: ignore
dur = dur_ns / 1_000_000
timings.data.append(f"total;dur={dur}")
response["Server-Timing"] = timings.serialize()
return response
Usage
def view(request: HttpRequest) -> HttpResponse:
with request.timings.timeit(name="Expensive query"):
...