Sentry
Enable Sentry with @repo/monitoring and wire it into a Next.js app.
Sentry monitors your application from backend to frontend. TurboJet ships the SDK inside @repo/monitoring — you configure env vars and wire each app that should report.
Not wired by default
Marketing and docs do not depend on @repo/monitoring yet. Follow the
wiring steps below to start sending events.
Create a Sentry project
- Sign up at Sentry and create an organization if needed.
- Create a project with the Next.js platform and copy the DSN.
Enable via environment
Add these to the root .env (see Environment):
NEXT_PUBLIC_ENABLE_SENTRY=true
NEXT_PUBLIC_SENTRY_DSN=https://…@….ingest.sentry.io/…
# Optional — source map uploads during build
SENTRY_AUTH_TOKEN=Sentry is active only when features.sentry is on (NEXT_PUBLIC_ENABLE_SENTRY !== "false") and NEXT_PUBLIC_SENTRY_DSN is non-empty (IS_SENTRY_ACTIVE in @repo/monitoring).
Create an auth token in the Sentry dashboard under Settings → Auth Tokens if you want source maps uploaded on build.
Customize build options
Edit org/project (and other options) in packages/monitoring/src/next-config.ts. Defaults today:
org:hilmirfs-orgproject:javascript-nextjstunnelRoute:/monitoring
withMonitoring wraps withSentryConfig and returns the unmodified Next config when Sentry is inactive.
Wire an app
Repeat for apps/marketing and/or apps/docs.
1. Add the dependency
Add @repo/monitoring as a workspace dependency of the app. Include it in transpilePackages in that app’s next.config if other workspace packages are listed there.
2. Wrap Next.js config
Marketing example (compose with existing plugins; order matters):
import { withMonitoring } from "@repo/monitoring/next-config";
export default withMonitoring(withNextIntl(nextConfig));For docs, wrap whatever you already export (for example withMDX(...)).
3. Server / edge instrumentation
Create src/instrumentation.ts:
import { initSentry } from "@repo/monitoring/config";
import { captureRequestError } from "@repo/monitoring/instrumentation";
export async function register() {
if (process.env.NEXT_RUNTIME === "nodejs") {
initSentry("server");
}
if (process.env.NEXT_RUNTIME === "edge") {
initSentry("edge");
}
}
export const onRequestError = captureRequestError;4. Client instrumentation
In the existing instrumentation-client.ts (PostHog already lives here), also init Sentry:
import { initPostHogClient } from "@repo/analytics/client";
import { initSentryClient } from "@repo/monitoring/client";
initPostHogClient();
initSentryClient();Do not import @repo/monitoring/client from edge/server instrumentation.
5. Global error handler
In src/app/global-error.tsx, report the error to Sentry:
"use client";
import * as Sentry from "@sentry/nextjs";
import { useEffect } from "react";
export default function GlobalError({
error,
}: {
error: Error & { digest?: string };
}) {
useEffect(() => {
Sentry.captureException(error);
}, [error]);
// ... existing UI
}6. Exclude the tunnel in proxy.ts
The Sentry tunnel is /monitoring. Extend the proxy matcher so i18n middleware does not rewrite it:
export const config = {
matcher: [
"/((?!api|monitoring|_next|_vercel|.*\\..*).*)",
],
};Capture from app code
Use helpers from @repo/monitoring when you need richer context:
import { addException, setUser } from "@repo/monitoring";
setUser({ user: { id: user.id, email: user.email } });
addException({
category: "api",
message: "Checkout failed",
error,
context: { orderId },
});