Structured Logging and Observability for the Django + FastAPI + Next.js Stack
Production-ready observability pattern with JSON logging, request correlation IDs, and queryable logs across frontend and backend—turning 3-hour debugging sessions into 20-minute fixes.
Structured Logging and Observability for the Django + FastAPI + Next.js Stack
Most logging setups are an afterthought—scattered print() calls, inconsistent levels, zero correlation between frontend and backend. When something breaks at 2 AM, that's the difference between a 20-minute fix and a 3-hour archaeology project.
This guide shows you a production-ready observability pattern across all three layers: Next.js, Django, and FastAPI. We'll use structured JSON logging, request correlation IDs, and make logs queryable in any sink (Loki, Datadog, CloudWatch).
The Core Principle: Structured Over Human-Readable
Log structured data, not strings. Instead of:
Log:
Every field is filterable. You can query level=error AND service=django-api AND duration_ms > 500 and get real answers.
Step 1: Correlation IDs — The Glue Across Services
A correlation ID (trace ID) is a UUID generated at the edge—frontend or API gateway—and forwarded through every downstream call. Without it, linking a frontend error to a backend exception is guesswork.
Next.js: Generate and forward
In middleware.ts:
In your fetch utility:
Step 2: Django — Structured Logging with python-json-logger
Install:
In settings.py:
Add middleware to extract and bind the trace ID:
Add TraceFilter to your handler and TraceIDMiddleware to MIDDLEWARE. Every Django log now carries the trace ID.
Step 3: FastAPI — Structlog for Async Logging
FastAPI's async model makes thread-locals unreliable. Use structlog with context variables:
Use in routes:
Step 4: Frontend Error Logging from Next.js
Client errors need to reach your logging endpoint:
Your /api/log handler writes this to stdout as JSON. Your log aggregator picks it up alongside backend logs—same structure, fully queryable.
Tying It Together
A single user-facing failure now produces correlated JSON lines across all services, all sharing the same trace_id. You can query that ID and reconstruct the full chain—frontend click, API call, database query, error—in order.
The implementation cost is minimal. The operational payoff when debugging production incidents is substantial. Structured logging isn't sophisticated observability; it's foundational. Get it in early.
Damian Hodgkiss
Senior Staff Engineer at Sumo Group, leading development of AppSumo marketplace. Technical solopreneur with 25+ years of experience building SaaS products.