Guides / Monitoring

How to Monitor Errors in Next.js App Router

4 min read·Monitoring

Where errors happen in App Router

Next.js App Router has three places where errors need to be caught:

  1. Server Actions — async server-side functions
  2. API Routesroute.ts handlers
  3. Client Components — React error boundaries (error.tsx)

1. Server Actions

ts
// lib/safe-action.ts
import { logit } from "@/lib/logit";

export function withErrorTracking<T extends unknown[], R>(
  fn: (...args: T) => Promise<R>
) {
  return async (...args: T): Promise<R> => {
    try {
      return await fn(...args);
    } catch (error) {
      await logit.now("errors", {
        event: "Server action error",
        description: error instanceof Error ? error.message : "Unknown error",
        icon: "❌",
        notify: true,
        metadata: {
          error: error instanceof Error ? error.message : String(error),
          stack: error instanceof Error ? error.stack?.slice(0, 500) : undefined,
        },
      });
      throw error;
    }
  };
}

// Usage:
export const createPost = withErrorTracking(async (data: PostData) => {
  // your action logic
});

2. API Routes

ts
// app/api/[...route]/route.ts
import { logit } from "@/lib/logit";

export async function POST(req: Request) {
  try {
    // your handler
    return Response.json({ ok: true });
  } catch (error) {
    await logit.now("errors", {
      event: "API route error",
      description: `POST ${new URL(req.url).pathname}: ${error instanceof Error ? error.message : "Unknown"}`,
      icon: "🔴",
      notify: true,
      metadata: {
        url: req.url,
        method: "POST",
        error: error instanceof Error ? error.message : String(error),
      },
    });
    return Response.json({ error: "Internal error" }, { status: 500 });
  }
}

3. Client Error Boundaries

tsx
// app/error.tsx
"use client";

export default function ErrorBoundary({ error, reset }: {
  error: Error & { digest?: string };
  reset: () => void;
}) {
  // Note: can't call logit directly from client — use an API route
  fetch("/api/log-error", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ message: error.message, digest: error.digest }),
  }).catch(() => {});

  return (
    <div>
      <h2>Something went wrong</h2>
      <button onClick={reset}>Try again</button>
    </div>
  );
}

Quick tip

Use notify: true only for production errors. In development, set:

ts
notify: process.env.NODE_ENV === "production",

Try LogIt free

7-day trial. No credit card required.

Start free