> ## Documentation Index
> Fetch the complete documentation index at: https://docs.hipocap.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Observability for Next.js

## Overview

[Next.js](https://nextjs.org/) is a popular React framework for building web applications.

<Note>
  For a full example app, see [the Next.js guide](/guides/nextjs) and the [Next.js + AI SDK guide](/guides/nextjs-aisdk).
</Note>

## Getting Started

### 1. Install Laminar

```bash theme={null}
npm add @lmnr-ai/lmnr
```

### 2. Update your next.config.ts

Add the following to your `next.config.ts` file:

```javascript next.config.ts theme={null}
const nextConfig = {
  serverExternalPackages: ['@lmnr-ai/lmnr'],
};

export default nextConfig;
```

This is because Laminar depends on OpenTelemetry, which uses some Node.js-specific functionality, and we need to inform Next.js about it. Learn more in the [Next.js docs](https://nextjs.org/docs/app/api-reference/config/next-config-js/serverExternalPackages).

### 3. Initialize Laminar

To instrument your entire Next.js app, place Laminar initialization in `instrumentation.{ts,js}` file. Learn more about `instrumentation.{ts,js}` [here](https://nextjs.org/docs/app/building-your-application/optimizing/instrumentation).

```typescript instrumentation.ts theme={null}
export async function register() {
  if (process.env.NEXT_RUNTIME === 'nodejs') {
    const { Laminar } = await import('@lmnr-ai/lmnr');
    Laminar.initialize({
      projectApiKey: process.env.LMNR_PROJECT_API_KEY,
    });
  }
}
```

<Note>
  `instrumentation.ts` is experimental in Next.js \< 15.
</Note>

If you use Next.js \< 15, add the following to your `next.config.js`:

```javascript next.config.js theme={null}
module.exports = {
    experimental: { instrumentationHook: true }
};
```

### 4. Patch LLM SDKs

<Tabs>
  <Tab title="AI SDKs">
    AI SDK is already instrumented implicitly, but you need to direct it to use Laminar tracer.

    ```javascript {3,8-11} theme={null}
    import { openai } from '@ai-sdk/openai';
    import { generateText } from 'ai';
    import { getTracer } from '@lmnr-ai/lmnr';

    const { text } = await generateText({
      model: openai('gpt-4.1-nano'),
      prompt: 'What is Laminar flow?',
      experimental_telemetry: {
        isEnabled: true,
        tracer: getTracer(),
      },
    });
    ```
  </Tab>

  <Tab title="Other LLM SDKs">
    Usually, Laminar initialize can patch the LLM SDKs automatically. However, in Next.js, the imports
    that happen in `instrumentation.{ts,js}` file are not visible to the rest of the app.

    So, you need to manually patch the LLM SDKs using `Laminar.patch` function.

    For example, if you initialize your LLM SDKs in `lib/llm-clients.ts` file, you can patch them like this:

    ```javascript lib/llm-clients.ts {3-8} theme={null}
    import { OpenAI } from "openai";
    import * as anthropic from "@anthropic-ai/sdk";
    import { Laminar } from "@lmnr-ai/lmnr";

    Laminar.patch({
      OpenAI: OpenAI,
      anthropic: anthropic,
    });

    const openai = new OpenAI();
    const anthropic = new anthropic.Anthropic();

    export { openai, anthropic };
    ```
  </Tab>
</Tabs>

### 5. Grouping traces within one route

If your app makes multiple LLM calls within one route, you may want to group them together.

You might get this functionality by default, if your app is instrumented with OpenTelemetry and
some Next.js instrumentation, e.g. `@vercel/otel` or `@sentry/nextjs`.

Otherwise, you can achieve this by using `observe` function wrapper, e.g. something like

```javascript app/api/chat/route.ts {1-2} theme={null}
import { NextRequest } from 'next/server';
import { getTracer, observe } from '@lmnr-ai/lmnr';

export const GET = observe(async (req: NextRequest) => {
  const tracer = getTracer();

  const { firstText, secondText } = await observe(
    {
      name: 'GET /api/chat',
    },
    async () => {
      const { firstText } = await generateText({
      model: openai('gpt-4.1-nano'),
      prompt: 'What is Laminar flow?',
      experimental_telemetry: {
        isEnabled: true,
        tracer,
      },
    });

    const { secondText } = await generateText({
      model: openai('gpt-4.1-nano'),
      prompt: 'What is Laminar flow?',
      experimental_telemetry: {
        isEnabled: true,
        tracer,
      },
    });

    return { firstText, secondText };
    }
  );

  return NextResponse.json({ firstText, secondText });
});
```

Learn more about `observe` in the SDK reference.
