--- title: "Monitoring and Error Tracking in Makerkit" status: "published" label: "How Monitoring Works" order: 0 description: "Set up error tracking and performance monitoring in your Next.js Supabase SaaS app with Sentry, PostHog, or SigNoz." --- {% sequence title="Steps to configure monitoring" description="Learn how to configure monitoring in the Next.js Supabase Starter Kit." %} [Understanding the monitoring architecture](#understanding-the-monitoring-architecture) [Supported monitoring providers](#supported-monitoring-providers) [Configuring your monitoring provider](#configuring-your-monitoring-provider) [What gets monitored automatically](#what-gets-monitored-automatically) [Manually capturing exceptions](#manually-capturing-exceptions) [Identifying users in error reports](#identifying-users-in-error-reports) {% /sequence %} ## Understanding the Monitoring Architecture Makerkit's monitoring system uses a **provider-based architecture** that lets you swap monitoring services without changing your application code. The system lives in the `@kit/monitoring` package and handles: - **Error tracking**: Capture client-side and server-side exceptions - **Performance monitoring**: Track server response times via OpenTelemetry instrumentation - **User identification**: Associate errors with specific users for debugging The architecture follows a registry pattern. When you set `NEXT_PUBLIC_MONITORING_PROVIDER`, Makerkit loads the appropriate service implementation at runtime: ``` MonitoringProvider (React context) │ ▼ Registry lookup │ ▼ ┌───────┴───────┐ │ sentry │ │ posthog │ │ signoz │ └───────────────┘ ``` This means your components interact with a consistent `MonitoringService` interface regardless of which provider you choose. ## Supported Monitoring Providers Makerkit provides first-class support for these monitoring providers: | Provider | Error Tracking | Performance | Self-Hostable | Notes | |----------|---------------|-------------|---------------|-------| | [Sentry](/docs/next-supabase-turbo/monitoring/sentry) | Yes | Yes | Yes | Built-in, recommended for most apps | | [PostHog](/docs/next-supabase-turbo/monitoring/posthog) | Yes | No | Yes | Plugin, doubles as analytics | | [SigNoz](/docs/next-supabase-turbo/monitoring/signoz) | Yes | Yes | Yes | Plugin, OpenTelemetry-native | **Sentry** is included out of the box. PostHog and SigNoz require installing plugins via the Makerkit CLI. {% alert type="default" title="Custom providers" %} You can add support for any monitoring service by implementing the `MonitoringService` interface and registering it in the provider registry. See [Adding a custom monitoring provider](#adding-a-custom-monitoring-provider) below. {% /alert %} ## Configuring Your Monitoring Provider Set these environment variables to enable monitoring: ```bash title=".env.local" # Required: Choose your provider (sentry, posthog, or signoz) NEXT_PUBLIC_MONITORING_PROVIDER=sentry # Provider-specific configuration # See the individual provider docs for required variables ``` The `NEXT_PUBLIC_MONITORING_PROVIDER` variable determines which service handles your errors. Leave it empty to disable monitoring entirely (errors still log to console in development). ## What Gets Monitored Automatically Once configured, Makerkit captures errors without additional code: ### Client-side exceptions The `MonitoringProvider` component wraps your app and captures uncaught exceptions in React components. This includes: - Runtime errors in components - Unhandled promise rejections - Errors thrown during rendering ### Server-side exceptions Next.js 15+ includes an instrumentation hook that captures server errors automatically. Makerkit hooks into this via `instrumentation.ts`: ```typescript title="apps/web/instrumentation.ts" import { type Instrumentation } from 'next'; export const onRequestError: Instrumentation.onRequestError = async ( err, request, context, ) => { const { getServerMonitoringService } = await import('@kit/monitoring/server'); const service = await getServerMonitoringService(); await service.ready(); await service.captureException( err as Error, {}, { path: request.path, headers: request.headers, method: request.method, routePath: context.routePath, }, ); }; ``` This captures errors from Server Components, Server Actions, Route Handlers, and Middleware. ## Manually Capturing Exceptions For expected errors (like validation failures or API errors), capture them explicitly: ### In Server Actions or Route Handlers ```typescript import { getServerMonitoringService } from '@kit/monitoring/server'; export async function createProject(data: FormData) { try { // ... your logic } catch (error) { const monitoring = await getServerMonitoringService(); await monitoring.ready(); monitoring.captureException(error, { action: 'createProject', userId: user.id, }); throw error; // Re-throw or handle as needed } } ``` ### In React Components Use the `useMonitoring` hook for client-side error capture: ```tsx 'use client'; import { useMonitoring } from '@kit/monitoring/hooks'; export function DataLoader() { const monitoring = useMonitoring(); async function loadData() { try { const response = await fetch('/api/data'); if (!response.ok) { throw new Error(`Failed to load data: ${response.status}`); } return response.json(); } catch (error) { monitoring.captureException(error, { component: 'DataLoader', }); throw error; } } // ... } ``` ### The `useCaptureException` Hook For error boundaries or components that receive errors as props: ```tsx 'use client'; import { useCaptureException } from '@kit/monitoring/hooks'; export function ErrorDisplay({ error }: { error: Error }) { // Automatically captures the error when the component mounts useCaptureException(error); return (
{error.message}