Production Engineering/
Lesson

In production, errors happen silently. A user hits a bug, gets frustrated, and leaves, and you never find out unless you have error tracking in place. Sentry is the industry standard tool for capturing, grouping, and alerting on runtimeWhat is runtime?The environment that runs your code after it's written. Some languages need a runtime installed on the machine; others (like Go) bake it into the binary. errors across your entire stack.

Think of Sentry like a flight recorder for your app. When something crashes, it captures everything: the stack traceWhat is stack trace?A list of function calls recorded at the moment an error occurs, showing exactly which functions were active and in what order., the browser version, the user's actions leading up to the error, and even the state of your variables. Without it, debugging production issues feels like investigating a plane crash with no black box.

Setting up Sentry

Installation and initialization

Install the Sentry SDKWhat is sdk?A pre-built library from a service provider that wraps their API into convenient functions you call in your code instead of writing raw HTTP requests. for your environment. For a Node.js backend:

npm install @sentry/node @sentry/tracing

For a React frontend:

npm install @sentry/react @sentry/tracing

Initialize Sentry as early as possible in your app, before any other imports if you can manage it. The dsn is the only required field, but you should always set environment dynamically:

import * as Sentry from '@sentry/node';

Sentry.init({
  dsn: process.env.SENTRY_DSN,
  environment: process.env.NODE_ENV,
  release: process.env.GIT_COMMIT_SHA,
  tracesSampleRate: 0.1, // Trace 10% of requests in production
});
Never hardcode `environment
'development'` in production code. Read it from an environment variable so the same build works in staging and production without changes.

Capturing errors manually

Sentry captures unhandled exceptions automatically, but you can also report errors explicitly when you catch and recover from them:

try {
  await processPayment(order);
} catch (err) {
  Sentry.captureException(err, {
    tags: { section: 'checkout' },
    extra: { orderId: order.id, amount: order.total },
  });
  // Show a user-friendly error, but still report to Sentry
  showErrorMessage('Payment failed. Please try again.');
}

This is especially valuable when you catch an error intentionally, Sentry won't see it unless you tell it.

02

Enriching errors with context

Identifying users

Raw error reports are hard to act on. Knowing who experienced the error lets you reach out directly and understand impact:

// Call this after a user logs in
Sentry.setUser({
  id: user.id,
  email: user.email,
  username: user.username,
});

// Clear on logout to avoid leaking identity
Sentry.setUser(null);

Adding breadcrumbs

Breadcrumbs are automatic for most browser events (clicks, navigation, XHR requests), but you can add custom ones for important business events:

Sentry.addBreadcrumb({
  category: 'checkout',
  message: 'User applied discount code',
  level: 'info',
  data: { code: 'SAVE20', valid: true },
});

When an error fires, you'll see exactly what the user did in the minutes before the crash. This is often more useful than the stack traceWhat is stack trace?A list of function calls recorded at the moment an error occurs, showing exactly which functions were active and in what order. itself.

03

Source maps for readable stack traces

Minified production code produces stack traces that look like a.b(c,d), completely useless. Source maps translate those back to your original TypeScript with real function names and line numbers.

Upload source maps as part of your build process:

# Using the Sentry CLI
npx @sentry/cli releases files "$RELEASE" upload-sourcemaps ./dist \
  --url-prefix '~/'

Or automate it with the Vite/webpack plugin:

// vite.config.ts
import { sentryVitePlugin } from '@sentry/vite-plugin';

export default {
  plugins: [
    sentryVitePlugin({
      org: 'your-org',
      project: 'your-project',
      authToken: process.env.SENTRY_AUTH_TOKEN,
    }),
  ],
  build: {
    sourcemap: true, // Required - generate source maps
  },
};
Source maps should never be publicly accessible. Upload them to Sentry and then delete them from your public deployment, or use hidden source maps that only Sentry can access.
04

Alerts and noise management

Setting up alert rules

Raw error volume is a poor signal. Configure Sentry alerts based on conditions that actually matter:

Alert typeWhen to useExample threshold
New issueFirst time an error appearsAlways alert
RegressionError returns after being resolvedAlways alert
Error spikeVolume increases sharply100% increase in 1 hour
High volumeError affects many users>50 users affected

Ignoring expected errors

Not every error deserves your attention. Filter out noise with beforeSend:

Sentry.init({
  dsn: process.env.SENTRY_DSN,
  beforeSend(event, hint) {
    const error = hint.originalException as Error;

    // Ignore network errors that are out of your control
    if (error?.message?.includes('Network request failed')) {
      return null; // Drop the event
    }

    return event; // Send everything else
  },
});
05

Quick reference

ConceptWhat it doesWhen to configure
dsnIdentifies your Sentry projectRequired, from environment variable
environmentTags errors by envSet from NODE_ENV
releaseTags errors by deploySet from git SHA or version
tracesSampleRateControls performance tracing volume0.1–0.3 in production
beforeSendFilter/modify events before sendingTo drop noise
setUser()Attach user identity to errorsAfter login
captureException()Manually report a caught errorIn catch blocks