Sentry provides a modular SDK strategy to handle error tracking and performance monitoring across different JavaScript runtimes. @sentry/browser is the core SDK for client-side web applications, capturing errors and performance data directly in the user's browser. @sentry/node is designed for server-side Node.js environments, focusing on backend errors, request tracing, and infrastructure issues. @sentry/react wraps the browser SDK with React-specific tools, offering components like Error Boundaries and hooks to seamlessly integrate error tracking into the React component lifecycle. Together, they allow developers to maintain full-stack visibility using a consistent API surface tailored to each environment's needs.
Sentry's JavaScript SDK is split into environment-specific packages to handle the unique challenges of client-side, server-side, and framework-specific development. While @sentry/browser, @sentry/node, and @sentry/react share a common core, they expose different tools optimized for their runtime. Let's compare how they handle initialization, error capturing, performance tracing, and context enrichment.
All three packages use the Sentry.init method, but they automatically configure different integrations based on the environment. This means you get relevant data out of the box without manual setup.
@sentry/browser configures integrations for the DOM and browser APIs.
// @sentry/browser: Client-side init
import * as Sentry from "@sentry/browser";
Sentry.init({
dsn: "https://examplePublicKey@o0.ingest.sentry.io/0",
// Automatically adds BrowserTracing and Breadcrumbs integrations
integrations: [Sentry.browserTracingIntegration()],
tracesSampleRate: 1.0,
});
@sentry/node configures integrations for the Node.js runtime.
// @sentry/node: Server-side init
import * as Sentry from "@sentry/node";
Sentry.init({
dsn: "https://examplePublicKey@o0.ingest.sentry.io/0",
// Automatically adds Http and Express integrations if detected
integrations: [Sentry.httpIntegration()],
tracesSampleRate: 1.0,
});
@sentry/react builds on top of the browser SDK with React-specific defaults.
// @sentry/react: React-specific init
import * as Sentry from "@sentry/react";
Sentry.init({
dsn: "https://examplePublicKey@o0.ingest.sentry.io/0",
// Includes React-specific error handling capabilities
integrations: [Sentry.browserTracingIntegration(), Sentry.reactRouterV6BrowserTracingIntegration()],
tracesSampleRate: 1.0,
});
How errors are caught differs significantly depending on whether you are in a global runtime, a server process, or a component tree.
@sentry/browser relies on global window handlers.
window.onerror and window.onunhandledrejection.// @sentry/browser: Global capture
import * as Sentry from "@sentry/browser";
// Manually capture an exception
try {
riskyOperation();
} catch (err) {
Sentry.captureException(err);
}
@sentry/node relies on process-level handlers.
process.on('uncaughtException').// @sentry/node: Process-level capture
import * as Sentry from "@sentry/node";
// Manually capture an exception in an API route
app.get("/user/:id", async (req, res) => {
try {
const user = await getUser(req.params.id);
res.json(user);
} catch (err) {
Sentry.captureException(err);
res.status(500).send("Error");
}
});
@sentry/react provides an ErrorBoundary component.
// @sentry/react: Component-level capture
import * as Sentry from "@sentry/react";
function App() {
return (
<Sentry.ErrorBoundary fallback={<p>An error has occurred</p>}>
<Profile />
</Sentry.ErrorBoundary>
);
}
// Or manually capture within a hook
function Component() {
const handleError = (error, eventId) => {
console.log("Error captured:", eventId);
};
return <Sentry.ErrorBoundary onError={handleError}>...</Sentry.ErrorBoundary>;
}
Performance monitoring is central to all three packages, but the focus shifts from user-centric metrics to server-centric latency.
@sentry/browser focuses on Web Vitals.
// @sentry/browser: User-centric tracing
import * as Sentry from "@sentry/browser";
Sentry.startSpan({ name: "myFunction" }, () => {
// Code to measure
doSomething();
});
@sentry/node focuses on Request Latency.
// @sentry/node: Request-centric tracing
import * as Sentry from "@sentry/node";
Sentry.startSpan({ name: "db-query" }, async () => {
// Database operation
await db.query("SELECT * FROM users");
});
@sentry/react focuses on Component Rendering.
// @sentry/react: Render-centric tracing
import * as Sentry from "@sentry/react";
function SlowComponent() {
return (
<Sentry.Profiler name="SlowComponent">
<div>Complex UI</div>
</Sentry.Profiler>
);
}
Adding context to errors helps developers filter and debug issues faster. All three packages share the same API for setting context, ensuring consistency across the stack.
@sentry/browser sets context for the end user.
// @sentry/browser: Set user context
import * as Sentry from "@sentry/browser";
Sentry.setUser({ id: "123", email: "user@example.com" });
Sentry.setTag("page_type", "checkout");
@sentry/node sets context for the request or server.
// @sentry/node: Set request context
import * as Sentry from "@sentry/node";
Sentry.setUser({ id: "123" });
Sentry.setTag("environment", "production");
@sentry/react sets context within the component tree.
// @sentry/react: Set context in component
import * as Sentry from "@sentry/react";
function Dashboard() {
Sentry.setTag("dashboard_view", "analytics");
return <div>...</div>;
}
Despite their environment-specific features, all three packages rely on the same underlying JavaScript SDK. This ensures a consistent developer experience when switching between frontend and backend code.
captureException, captureMessage, and setContext work identically.// Works in browser, node, and react
Sentry.captureMessage("Something happened");
Sentry.setContext("character", { name: "Mario", level: 5 });
// Configured in init for all packages
Sentry.init({
dsn: "...",
beforeSend(event) {
// Scrub sensitive data
if (event.request) {
delete event.request.cookies;
}
return event;
},
});
// Set release in init for all packages
Sentry.init({
dsn: "...",
release: "my-project@1.0.0",
});
# Command line usage is the same for all
sentry-cli sourcemaps upload ./dist
// Custom integration example
const myIntegration = {
name: "MyIntegration",
setupOnce() {
// Custom setup logic
},
};
Sentry.init({
integrations: [myIntegration],
});
| Feature | @sentry/browser | @sentry/node | @sentry/react |
|---|---|---|---|
| Runtime | 🌐 Web Browser | 🖥️ Node.js Server | ⚛️ React (Client) |
| Error Boundary | ❌ No | ❌ No | ✅ Yes (ErrorBoundary) |
| Tracing Focus | 📱 Web Vitals & Network | 🗄️ DB Queries & HTTP Requests | 🎨 Component Renders |
| Integrations | DOM, Fetch, XHR | Express, HTTP, MongoDB | React Router, Profiler |
| Use Case | Vanilla JS, Generic Frontend | APIs, Backend Services | React SPAs, Next.js Client |
@sentry/browser is the foundation for client-side tracking. Use it when you need a lightweight solution for standard web pages or when you are not using a framework with a dedicated SDK. It gives you direct access to browser internals without extra abstraction.
@sentry/node is the backbone for server-side observability. It is non-negotiable for Node.js backends, ensuring that errors occurring on the server are not invisible. It focuses on request lifecycles and infrastructure health.
@sentry/react is the specialized tool for modern frontend development. It bridges the gap between generic browser tracking and the specific needs of React applications, particularly regarding component errors and rendering performance.
Final Thought: In a full-stack application, you will often use @sentry/node on your API server and @sentry/react on your frontend. They work together to provide a complete trace from the user's click to the database query, allowing you to debug issues across the entire system with a single tool.
Choose @sentry/browser if you are building a vanilla JavaScript application or using a framework that does not have a dedicated Sentry SDK (like Svelte or Angular, though they have their own, sometimes browser is used for generic setups). It is the right fit when you need direct access to browser-specific APIs like Breadcrumbs from console logs or DOM interactions without the overhead of React integrations. Use this for lightweight client-side scripts or when you need full control over the initialization without framework-specific abstractions.
Choose @sentry/node when you need to monitor server-side code, such as Express APIs, NestJS applications, or serverless functions running on Node.js. It is essential for capturing uncaught exceptions, handling request tracing for incoming HTTP calls, and monitoring database queries. This package is mandatory for backend services where browser APIs are unavailable and you need to track errors that occur before the response reaches the client.
Choose @sentry/react for any application built with React, including Single Page Applications (SPAs) and hybrid frameworks like Next.js or Remix (on the client side). It is the best choice because it provides the ErrorBoundary component, which catches React render errors that the standard browser SDK might miss. Use this to leverage hooks for performance profiling and to ensure that component tree errors are reported with proper context about the React hierarchy.
To use this SDK, call Sentry.init(options) as early as possible after loading the page. This will initialize the SDK
and hook into the environment. Note that you can turn off almost all side effects using the respective options.
import * as Sentry from '@sentry/browser';
Sentry.init({
dsn: '__DSN__',
// ...
});
To set context information or send manual events, use the exported functions of @sentry/browser. Note that these
functions will not perform any action before you have called Sentry.init():
import * as Sentry from '@sentry/browser';
// Set user information, as well as tags and further extras
Sentry.setExtra('battery', 0.7);
Sentry.setTag('user_mode', 'admin');
Sentry.setUser({ id: '4711' });
// Add a breadcrumb for future events
Sentry.addBreadcrumb({
message: 'My Breadcrumb',
// ...
});
// Capture exceptions, messages or manual events
Sentry.captureMessage('Hello, world!');
Sentry.captureException(new Error('Good bye'));
Sentry.captureEvent({
message: 'Manual',
stacktrace: [
// ...
],
});