For AI agents: a documentation index is available at the root level at /llms.txt and /llms-full.txt. Append /llms.txt to any URL for a page-level index, or .md for the markdown version of any page.
Sign inTry it free
DocsGuidesSDKsIntegrationsAPI docsTutorialsFlagship blog
DocsGuidesSDKsIntegrationsAPI docsTutorialsFlagship blog
  • Tutorials
    • The human-in-the-loop alternative to autonomous remediation
    • The AI Iteration Loop for Deploying Reliable Agents with LangGraph
    • Using LaunchDarkly feature flags and Experimentation with Wordpress
    • Migrate a Hardcoded LangGraph Agent to LaunchDarkly AgentControl in 20 Minutes
    • Offline Evaluation of RAG-Grounded Answers in AgentControl
    • Beyond n8n for Workflow Automation: Agent Graphs as Your Universal Agent Harness
    • Catch your first silent AI failure with Vega AI in under 10 minutes
    • Evaluate LLM code generation with LLM-as-judge evaluators
    • OpenTelemetry for LLM Applications: A Practical Guide with LaunchDarkly and Langfuse
    • Use LaunchDarkly Agent Skills in Claude Code and Cursor
    • Detection to Resolution: Real World Debugging with Rage Clicks and Session Replay
    • Compare AI orchestrators: LangGraph vs Strands vs OpenAI Swarm
    • Building a data extraction pipeline with LaunchDarkly
    • Day 12 | 🎊 New Year, New Observability
    • Day 11 | ✉️ Letters to Santa: What engineering teams really want from Observability in 2026
    • Day 10 | Why observability and feature flags go together like milk and cookies
    • Day 9 | 👻 The Three Ghosts Haunting Your AI This Holiday Season
    • Day 7 | 🎄✨The Rockefeller tree in NYC: SLOs that actually drive decisions
    • Day 6 | 💸 The famous green character that stole your cloud budget: the cardinality problem
    • Day 5 | 🧹 Using a Popular Tidying Method to Consolidate Your Observability Stack
    • Day 4 | ❄️ Tracing the impact of holiday styling in your Node.js app
    • Day 8 | 🎁 Observable Multi-Modal Agentic Systems
    • Day 3 | 🔔 Jingle All the Way to Zero-Config Observability
    • Day 2 | 🎅 He knows if you have been bad or good... But what if he gets it wrong?
    • Collecting user feedback in your app with feature flags
    • Day 1 | 🎄 Observability Under the Tree: What Changed in 2025
    • Build a User Frustration Detection & Response System
    • When to Add Online Evals to Your AgentControl
    • Detecting User Frustration: Understanding Rage Clicks and Session Replay
    • AgentControl config CI/CD Pipeline: Automated Quality Gates and Safe Deployment
    • A Deeper Look at LaunchDarkly Architecture: More than Feature Flags
    • Add Observability to Your React Native App in 5 minutes
    • Smart AI Agent Targeting with MCP Tools
    • Build a LangGraph Multi-Agent System in 20 Minutes with LaunchDarkly AgentControl
    • Snowflake Cortex Completion API + LaunchDarkly SDK Integration
    • Using AgentControl to review database changes
    • How to implement WebSockets and kill switches in a Python application
    • 4 hacks to turbocharge your Cursor productivity
    • Create a feature flag in your IDE in 5 minutes with LaunchDarkly's MCP server
    • Observability for Your Go ORM: OpenTelemetry Integration with GORM
    • The complete guide to OpenTelemetry in Next.js
    • How to instrument your React Native app with OpenTelemetry
    • The complete guide to OpenTelemetry in Python
    • Monitoring Browser Applications with OpenTelemetry
    • How to Use OpenTelemetry to Monitor Next.js Applications
    • What is OpenTelemetry and Why Should I Care?
    • Distributed Tracing in Next.js Apps
    • Tracing Distributed Systems in Next.js
    • Real-time Monitoring in Django: Essential Tools and Techniques
    • DeepSeek vs Qwen: local model showdown featuring LaunchDarkly AgentControl
    • Application Tracing in .NET for Performance Monitoring
    • The Ultimate Guide to Ruby Logging: Best Libraries and Practices
    • Using Materialized Views in ClickHouse (vs. Postgres)
    • Filtering and Sampling LaunchDarkly Ingest
    • How to Set Up Your Production AWS MSK Kafka Cluster
    • Publishing an NPM Package with Private pnpm Monorepo Dependencies
    • How To Use The Chrome Inspector & Debugger
    • 3 Levels of Data Validation in a Full Stack Application With React
    • The power of the monorepo: Keep your fullstack app in sync!
    • Compression: The simple, powerful upgrade for your web stack
    • Video tutorials
Sign inTry it free
LogoLogo
On this page
  • Distributed Tracing
  • Approach
  • Instrumenting the Next.js web client
  • Calling the Next.js API function
  • Wrapping Next.js API functions
  • Configure our Golang service
  • W3C traceparent example code
  • Result
Tutorials

Tracing Distributed Systems in Next.js

Was this page helpful?
Previous

Real-time Monitoring in Django: Essential Tools and Techniques

Next
Built with

Published April 21, 2024

portrait of Chris Esplin.

by Chris Esplin

Watch on YouTube

Distributed Tracing

Distributed tracing is crucial for debugging and improving system performance. Instead of looking at the performance of each service in isolation, distributed tracing links traces across services to show how a request flows through a system. For instance, a trace might start in a React web client, pass through a Next.js API, and continue across subsequent HTTP calls, keeping all activities under one umbrella. This not only simplifies tracking but also provides a clear, consolidated view of how different parts of your application interact.

Distributed tracing flame graph showing how a request flows across multiple services.

Distributed tracing flame graph showing how a request flows across multiple services.

Approach

In this post, we’ll go over a practical example of how tracing across multiple services work in the context of a modern NextJS application.

Here’s the exact github repo we’ll be pulling the example from:

GitHub: Distributed Tracing Example

We will demonstrate how to use LaunchDarkly to connect a NextJS application with an external service by passing HTTP headers in the following steps:

  • Next Client: The web client initiates an HTTP Fetch request, passing the x-highlight-request header which contains a generated sessionId and requestId.
  • Next Server: A Next.js API function receives that request, associates the sessionId and requestId to it’s local trace, then passes the x-highlight-request header to a third service, this time written in Golang.
  • Go Server: The Golang service receives the x-highlight-request header and associates it to the local trace.

Instrumenting the Next.js web client

Client-side integration is as easy as injecting <HighlightInit /> into your web app.

  • Inject <HighlightInit /> once, preferably in a layout.tsx file or _app.tsx file.
  • <HighlightInit /> accepts props that correspond to the JavaScript SDK’s options arguments.
  • Explore LaunchDarkly’s wide range of configuration options, including
    • Canvas and WebGL support,
    • user identification,
    • and privacy and redaction.
1// app/layout.tsx
2import { CONSTANTS } from "../constants";
3import { HighlightInit } from "@highlight-run/next/client";
4
5export default function RootLayout({
6 children,
7}: {
8 children: React.ReactNode;
9}) {
10 return (
11 <>
12 <HighlightInit
13 // excludedHostnames={['localhost']}
14 projectId={CONSTANTS.ENV.HIGHLIGHT.PROJECT_ID}
15 serviceName="my-nextjs-frontend"
16 tracingOrigins
17 networkRecording={{
18 enabled: true,
19 recordHeadersAndBody: true,
20 }}
21 debug
22 />
23
24 <html lang="en">
25 <body>{children}</body>
26 </html>
27 </>
28 );
29}

Calling the Next.js API function

We’ll use the browser’s Fetch API to call a Next.js API function. LaunchDarkly monkey patches window.fetch and adds the x-highlight-request header automatically, so use Fetch as you normally would.

See the full list of monkey patches in our docs.

1 <button
2 onClick={async () => {
3 await fetch("/propagation-test");
4 }}
5>Trigger propagation</button>

Wrapping Next.js API functions

First, create a wrapper function. The Next.js SDK wrapper functions capture incoming headers and wrap the handler in a custom span named highlight-run-with-headers.

In this case, we’re using the App Router, so we’ll follow the Next.js App Router Guide.

1// utils/app-router-highlight.config.ts:
2import { AppRouterHighlight } from "@highlight-run/next/server";
3import { CONSTANTS } from "../../constants";
4
5export const withAppRouterHighlight = AppRouterHighlight({
6 projectID: CONSTANTS.ENV.HIGHLIGHT.PROJECT_ID,
7});

Next, we wrap our GET handler function. Note that we wrap our handler function with withAppRouterHighlight, and we forward request.headers along with the next HTTP request.

The x-highlight-request header is only header that matters in this example.

1// app/propagation-test/route.ts
2import { NextRequest } from "next/server";
3import { withAppRouterHighlight } from "../_utils/app-router-highlight.config";
4
5export const GET = withAppRouterHighlight(async (request: NextRequest) => {
6 console.info("Here: app/propagation-test/route.ts");
7
8 const response = await fetch("http://localhost:3010/test", {
9 method: "GET",
10 headers: request.headers, // x-highlight-request is the critical header
11 });
12
13 const data = await response.text();
14
15 return new Response(data);
16});

Configure our Golang service

LaunchDarkly supports multiple Go libraries. In this case we’re using the LaunchDarkly chi SDK.

See a working example of LaunchDarkly chi implementation on GitHub.

First, we configure the highlight-go SDK.

1import (
2 "github.com/highlight/highlight/sdk/highlight-go"
3)
4
5func main() {
6 // ...
7 highlight.SetProjectID("<YOUR_PROJECT_ID>")
8 highlight.Start(
9 highlight.WithServiceName("my-app"),
10 highlight.WithServiceVersion("git-sha"),
11 )
12 defer highlight.Stop()
13 // ...
14}

Next we add the Chi middleware.

1import (
2 highlightChi "github.com/highlight/highlight/sdk/highlight-go/middleware/chi"
3)
4
5func main() {
6 // ...
7 r := chi.NewRouter()
8 r.Use(highlightChi.Middleware)
9 // ...
10}

The highlightChi.Middleware function will automatically associate the current request with the incoming x-highlight-request header.

W3C traceparent example code

We used the x-highlight-request header in this example, but we also tested OpenTelemetry’s native JavaScript Propagation example using the W3C traceparent header.

Instead of passing x-highlight-request header, it is possible to pass a traceparent header across HTTP calls. It’s a bit involved, but it works great. See the links below for example code:

  • withPropagation: an example wrapper for Next.js
  • GET route: Pass request.headers along as before.
  • Golang example: Associate the incoming traceparent header with a local trace.

Result

All three services, the web client, the Next.js API function, and the Golang backend, now feed their data to the same LaunchDarkly project.

For the purposes of example, we can even visualize this data in our product (and open source application monitoring tool), LaunchDarkly!

This example shows four separate spans, all of which are nested under a single trace. And of course, these traces are accessible from LaunchDarkly’s Session Replay tab, because the session was generated in the web client and propagated throughout the entire distributed “call stack”.

  • highlight-run-with-headers is generated by the AppRouterHighlight wrapper function in Next.js.
  • fetch GET https://localhost:3010/test is generated by the Next.js Fetch request.
  • highlight.chi is created by LaunchDarkly’s chi middleware.
  • go-custom-span is a custom span that we used in our example code for demonstration purposes. It wraps a call to time.Sleep(1 * time.Second) to mimic slow code execution.

LaunchDarkly trace view showing the highlight-run-with-headers span wrapping the distributed request.

LaunchDarkly trace view showing the highlight-run-with-headers span wrapping the distributed request.

highlight-run-with-headers

LaunchDarkly trace view showing the go-custom-span from the Golang backend service.

LaunchDarkly trace view showing the go-custom-span from the Golang backend service.

go-custom-span