Skip to main content
Technology & EngineeringMonitoring Services257 lines

Sentry

Sentry: error tracking, performance monitoring, session replay, source maps, breadcrumbs, Next.js/React SDK, alerts

Quick Summary18 lines
Sentry is an application monitoring platform focused on error tracking and performance monitoring. The guiding principles are:

## Key Points

- **Capture every error with context** — stack traces alone are insufficient; breadcrumbs, user context, and environment data turn noise into actionable insight.
- **Performance is a feature** — track transaction durations, web vitals, and database queries to find bottlenecks before users complain.
- **Source maps are non-negotiable** — minified stack traces are useless; always upload source maps in CI so production errors point to original source lines.
- **Alert on impact, not volume** — configure alerts based on issue frequency, affected users, or regression detection rather than raw error counts.
- **Release tracking closes the loop** — tie errors to specific deploys so you know exactly which commit introduced a regression.
1. **Set `tracesSampleRate` low in production** — 0.1 to 0.2 is typical; 1.0 will blow through quotas and add overhead.
2. **Use `beforeSend` to scrub PII** — strip emails, tokens, and passwords from error payloads before they leave the client.
3. **Tag errors by feature area** — use `Sentry.setTag("feature", "checkout")` so you can filter dashboards per team.
4. **Configure alert rules for regressions** — Sentry can detect when a previously resolved issue reappears after a deploy.
5. **Use the tunnel route in Next.js** — the `/monitoring` tunnel bypasses ad-blockers that strip Sentry requests.
6. **Upload source maps in CI, not at build time** — keeps your build fast and ensures maps are always tied to a release.
7. **Set meaningful release names** — use short git SHAs or semantic versions so the Releases dashboard is navigable.
skilldb get monitoring-services-skills/sentryFull skill: 257 lines
Paste into your CLAUDE.md or agent config

Sentry Monitoring Skill

Core Philosophy

Sentry is an application monitoring platform focused on error tracking and performance monitoring. The guiding principles are:

  • Capture every error with context — stack traces alone are insufficient; breadcrumbs, user context, and environment data turn noise into actionable insight.
  • Performance is a feature — track transaction durations, web vitals, and database queries to find bottlenecks before users complain.
  • Source maps are non-negotiable — minified stack traces are useless; always upload source maps in CI so production errors point to original source lines.
  • Alert on impact, not volume — configure alerts based on issue frequency, affected users, or regression detection rather than raw error counts.
  • Release tracking closes the loop — tie errors to specific deploys so you know exactly which commit introduced a regression.

Setup

Next.js SDK Installation

// Install dependencies
// npm install @sentry/nextjs

// sentry.client.config.ts
import * as Sentry from "@sentry/nextjs";

Sentry.init({
  dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
  environment: process.env.NODE_ENV,
  release: process.env.SENTRY_RELEASE,
  tracesSampleRate: process.env.NODE_ENV === "production" ? 0.2 : 1.0,
  replaysSessionSampleRate: 0.1,
  replaysOnErrorSampleRate: 1.0,
  integrations: [
    Sentry.replayIntegration({
      maskAllText: false,
      blockAllMedia: false,
    }),
    Sentry.browserTracingIntegration(),
  ],
  ignoreErrors: [
    "ResizeObserver loop limit exceeded",
    "Network request failed",
    /Loading chunk \d+ failed/,
  ],
});

Server-Side Configuration

// sentry.server.config.ts
import * as Sentry from "@sentry/nextjs";

Sentry.init({
  dsn: process.env.SENTRY_DSN,
  environment: process.env.NODE_ENV,
  release: process.env.SENTRY_RELEASE,
  tracesSampleRate: 0.2,
  profilesSampleRate: 0.1,
  integrations: [
    Sentry.prismaIntegration(),
  ],
  beforeSend(event) {
    if (event.exception?.values?.[0]?.type === "HealthCheckError") {
      return null; // Drop health check noise
    }
    return event;
  },
});

Next.js Config Integration

// next.config.ts
import { withSentryConfig } from "@sentry/nextjs";

const nextConfig = {
  // your existing config
};

export default withSentryConfig(nextConfig, {
  org: process.env.SENTRY_ORG,
  project: process.env.SENTRY_PROJECT,
  authToken: process.env.SENTRY_AUTH_TOKEN,
  silent: true,
  hideSourceMaps: true,
  widenClientFileUpload: true,
  tunnelRoute: "/monitoring", // Bypass ad-blockers
});

Key Techniques

Structured Error Boundaries

// components/SentryErrorBoundary.tsx
import * as Sentry from "@sentry/nextjs";
import { Component, type ErrorInfo, type ReactNode } from "react";

interface Props {
  fallback: ReactNode;
  children: ReactNode;
  context?: string;
}

interface State {
  hasError: boolean;
  eventId: string | null;
}

export class SentryErrorBoundary extends Component<Props, State> {
  state: State = { hasError: false, eventId: null };

  static getDerivedStateFromError(): Partial<State> {
    return { hasError: true };
  }

  componentDidCatch(error: Error, info: ErrorInfo) {
    const eventId = Sentry.captureException(error, {
      contexts: {
        react: { componentStack: info.componentStack },
        feature: { area: this.props.context ?? "unknown" },
      },
    });
    this.setState({ eventId });
  }

  render() {
    if (this.state.hasError) {
      return this.props.fallback;
    }
    return this.props.children;
  }
}

Custom Breadcrumbs and Context

// lib/sentry-helpers.ts
import * as Sentry from "@sentry/nextjs";

export function trackUserAction(action: string, data?: Record<string, unknown>) {
  Sentry.addBreadcrumb({
    category: "user-action",
    message: action,
    data,
    level: "info",
  });
}

export function setUserContext(user: { id: string; email: string; plan: string }) {
  Sentry.setUser({ id: user.id, email: user.email });
  Sentry.setTag("plan", user.plan);
  Sentry.setContext("subscription", { plan: user.plan });
}

export function captureBusinessError(
  message: string,
  metadata: Record<string, unknown>
) {
  Sentry.captureMessage(message, {
    level: "warning",
    tags: { domain: "business-logic" },
    extra: metadata,
  });
}

Performance Transactions

// lib/sentry-perf.ts
import * as Sentry from "@sentry/nextjs";

export async function tracedOperation<T>(
  name: string,
  op: string,
  fn: () => Promise<T>
): Promise<T> {
  return Sentry.startSpan(
    { name, op, attributes: { "code.function": name } },
    async (span) => {
      try {
        const result = await fn();
        span.setStatus({ code: 1, message: "ok" });
        return result;
      } catch (error) {
        span.setStatus({ code: 2, message: "error" });
        Sentry.captureException(error);
        throw error;
      }
    }
  );
}

// Usage in an API route
export async function POST(request: Request) {
  return tracedOperation("create-order", "http.server", async () => {
    const body = await request.json();
    const order = await tracedOperation("db.insert-order", "db.query", () =>
      db.order.create({ data: body })
    );
    await tracedOperation("email.send-confirmation", "queue.publish", () =>
      emailQueue.send({ orderId: order.id })
    );
    return Response.json(order);
  });
}

Source Map Upload in CI

// scripts/sentry-release.ts
import { execSync } from "child_process";

const version = process.env.GITHUB_SHA?.slice(0, 7) ?? "local";
const org = process.env.SENTRY_ORG!;
const project = process.env.SENTRY_PROJECT!;

function run(cmd: string) {
  execSync(cmd, { stdio: "inherit" });
}

run(`sentry-cli releases new ${version} --org ${org} --project ${project}`);
run(`sentry-cli releases files ${version} upload-sourcemaps .next --org ${org} --project ${project}`);
run(`sentry-cli releases set-commits ${version} --auto --org ${org} --project ${project}`);
run(`sentry-cli releases finalize ${version} --org ${org} --project ${project}`);
run(`sentry-cli releases deploys ${version} new -e production --org ${org} --project ${project}`);

Best Practices

  1. Set tracesSampleRate low in production — 0.1 to 0.2 is typical; 1.0 will blow through quotas and add overhead.
  2. Use beforeSend to scrub PII — strip emails, tokens, and passwords from error payloads before they leave the client.
  3. Tag errors by feature area — use Sentry.setTag("feature", "checkout") so you can filter dashboards per team.
  4. Configure alert rules for regressions — Sentry can detect when a previously resolved issue reappears after a deploy.
  5. Use the tunnel route in Next.js — the /monitoring tunnel bypasses ad-blockers that strip Sentry requests.
  6. Upload source maps in CI, not at build time — keeps your build fast and ensures maps are always tied to a release.
  7. Set meaningful release names — use short git SHAs or semantic versions so the Releases dashboard is navigable.
  8. Add breadcrumbs at key user flows — login, checkout, file upload; these provide the "what happened before the crash" timeline.

Anti-Patterns

  1. Catching and swallowing errorstry { ... } catch (e) { console.log(e) } hides failures from Sentry entirely. Re-throw or call captureException.
  2. Sample rate of 1.0 in production — generates massive data volumes, inflates costs, and can degrade app performance.
  3. Ignoring source maps — reading minified stack traces wastes hours of debugging time; always upload maps.
  4. Alerting on every single error — leads to alert fatigue. Alert on frequency spikes, new issues, or regressions instead.
  5. Storing secrets in Sentry context — never attach API keys, passwords, or tokens to error events. Use beforeSend to filter.
  6. Skipping environment configuration — without it, staging and production errors mix together, making triage impossible.
  7. Not setting user context — without Sentry.setUser(), you cannot tell how many unique users are affected by an issue.

Install this skill directly: skilldb add monitoring-services-skills

Get CLI access →