Next.js

Use the Middleware Next.js APM package to collect traces, metrics and application logs from server components, API routes and middleware in a Next.js app. The table shows which data types it collects.

TracesMetricsApp LogsCustom LogsProfiling
✅✖✖✅✅

1. Prerequisites#

  • Next.js 13.4+ (instrumentation file support). Check:
    javascript
    npx next --version
  • Enable the instrumentation hook. In Next.js, the instrumentation.ts file is wired via the experimental instrumentationHook flag (still documented as experimental).
  • OpenTelemetry API peer range (required by the agent):
    javascript
    npm i @opentelemetry/api@">=1.3.0 <1.5.0"
  • (Optional but recommended) Middleware Host Agent on the same host/cluster. In containers, set MW_AGENT_SERVICE so your app can reach the agent:
    • Docker: MW_AGENT_SERVICE=172.17.0.1
    • Kubernetes: MW_AGENT_SERVICE=mw-service.mw-agent-ns.svc.cluster.local

2. Install the Next.js APM package#

bash
npm install @middleware.io/agent-apm-nextjs

3. Modify next.config.js#

Add the instrumentation flag. For newer projects, it’s also recommended to allow the package in server components’ externals:

javascript
// next.config.js
const nextConfig = {
  experimental: {
    instrumentationHook: true,
    // recommended on modern projects
    serverComponentsExternalPackages: ['@middleware.io/agent-apm-nextjs'],
  },
};
module.exports = nextConfig;

This mirrors the package guidance and Next.js’ own docs on enabling the instrumentation hook.

4. Create the instrumentation file#

Place instrumentation.ts (or .js) at the project root (or inside src/ if you use a src directory). The file must export a register() function as Next.js calls it once when a server instance boots.

With Host Agent (default path):

javascript
// instrumentation.ts
// @ts-expect-error: type declarations are not yet complete
import tracker from '@middleware.io/agent-apm-nextjs';

export function register() {
  tracker.track({
    serviceName: '{APM-SERVICE-NAME}',
    accessToken: '<MW_API_KEY>',
  });
}

Serverless / no Host Agent (send direct to Middleware):

javascript
// instrumentation.ts
import tracker from '@middleware.io/agent-apm-nextjs';

export function register() {
  tracker.track({
    serviceName: '{APM-SERVICE-NAME}',
    accessToken: '<MW_API_KEY>',
    target: 'https://<MW_UID>.middleware.io:443',
  });
}

If you customise pagesExtension, ensure the filename matches (e.g., instrumentation.ts).

5. Container variables (only if using the Host Agent)#

Docker

bash
MW_AGENT_SERVICE=172.17.0.1
  • (172.17.0.1 is Docker’s default bridge gateway.)

Kubernetes

bash
MW_AGENT_SERVICE=mw-service.mw-agent-ns.svc.cluster.local

You can locate the service with:

bash
kubectl get service --all-namespaces | grep mw-service

6. Enable custom logs (optional)#

Use the logger helpers anywhere in your API routes, Route Handlers, or server actions:

javascript
// @ts-expect-error
import tracker from '@middleware.io/agent-apm-nextjs';

export default async function handler(req, res) {
  tracker.info('Info Sample');
  tracker.warn('Warn Sample', { tester: 'Alex' });
  tracker.debug('Debug Sample');
  tracker.error('Error Sample');
  // ...
}

7. View your Data#

After deploy/startup, wait 3–5 minutes and then open APM → Traces, Logs, and APM → Continuous Profiling in your Middleware account. (For Next.js, metrics and app-logs are not collected by this agent; use Custom Logs as shown above.)

8. Environment variables#

These mirror the options you’d otherwise pass in tracker.track(...).

VariablePurposeExample
MW_API_KEYAuthentication token for exports.xxxxxxxx…
MW_TARGETOTLP endpoint (serverless/remote). Defaults to Host Agent when omitted.https://<MW_UID>.middleware.io:443
MW_SERVICE_NAMEAPM service identifier.nextjs-web
MW_PROJECT_NAMELogical project/app name (optional).ShopApp
MW_CONSOLE_EXPORTEREcho spans/logs to the console for local verification.true
MW_AGENT_SERVICEHost/Service for the Agent when in containers.172.17.0.1 or mw-service.mw-agent-ns.svc.cluster.local

9. Troubleshooting quick checks#

  • register() didn’t run / no traces: ensure experimental.instrumentationHook: true is set and the file is named and placed correctly (root or src/).
  • On Vercel builds: also include serverComponentsExternalPackages: ['@middleware.io/agent-apm-nextjs'] as recommended by the package and Vercel integration notes.
  • Container reachability: set MW_AGENT_SERVICE as shown above.

Need assistance or want to learn more about Middleware? Get in touch with us via our Contact Us or join our Slack channel.

What did you think of this content?