The @sentry/node package provides error tracking and performance monitoring for Node.js applications using OpenTelemetry for automatic instrumentation.
Prerequisites
- Node.js 18 or newer
- A Sentry account and project DSN
Installation
Install the Package
Install @sentry/node using your preferred package manager:Current Version: 10.42.0 Create Instrumentation File
Create a file named instrument.js (or instrument.mjs for ESM) that initializes Sentry. This file must be imported before any other modules:// instrument.js
const Sentry = require('@sentry/node');
Sentry.init({
dsn: 'YOUR_DSN_HERE',
// Set tracesSampleRate to 1.0 to capture 100%
// of transactions for tracing
tracesSampleRate: 1.0,
});
You must call Sentry.init() before requiring/importing any other modules. This ensures that Sentry can automatically instrument all modules in your application.
Import Instrumentation in Your Application
Import the instrumentation file as the first import in your application:// app.js
// Import this first!
require('./instrument');
// Now import other modules
const express = require('express');
const http = require('http');
// Your application code
const app = express();
// ...
ESM: Use --import Flag (Recommended)
For ESM applications, use Node.js’s --import flag to ensure Sentry loads before your application:# Node.js 18.19.0 and newer
node --import ./instrument.mjs app.mjs
Or set it via environment variable:NODE_OPTIONS="--import ./instrument.mjs" npm run start
Using --import ensures that Sentry is initialized before any application code runs, providing the most complete instrumentation.
Verify Installation
Test that Sentry is working:import * as Sentry from '@sentry/node';
// This will create an error and send it to Sentry
Sentry.captureException(new Error('Test error'));
// Flush events before the application exits
await Sentry.flush(2000);
Check your Sentry dashboard to see the error.
Automatic Instrumentation
The Node.js SDK uses OpenTelemetry to automatically instrument popular frameworks and libraries:
- HTTP/HTTPS:
http, https, node-fetch, undici
- Databases: PostgreSQL, MySQL, MySQL2, MongoDB, Mongoose, Redis, Prisma
- Frameworks: Express, Fastify, Koa, Hapi, Connect, NestJS
- GraphQL: GraphQL server instrumentation
- Message Queues: Kafka, AMQP
- Other: Knex, Tedious, Generic Pool, Dataloader
All automatic instrumentation happens when you call Sentry.init() before importing other modules. No additional configuration is required.
Framework Integrations
Express
import express from 'express';
import * as Sentry from '@sentry/node';
const app = express();
// Request handler must be the first middleware
app.use(Sentry.expressIntegration());
// Your routes
app.get('/', (req, res) => {
res.send('Hello World!');
});
// Error handler must be before any other error middleware
app.use(Sentry.expressErrorHandler());
// Optional fallthrough error handler
app.use((err, req, res, next) => {
res.statusCode = 500;
res.end('Internal Server Error');
});
app.listen(3000);
Fastify
import Fastify from 'fastify';
import * as Sentry from '@sentry/node';
const fastify = Fastify();
// Register Sentry plugin
await fastify.register(Sentry.fastifyIntegration());
// Set up error handler
await Sentry.setupFastifyErrorHandler(fastify);
fastify.get('/', async (request, reply) => {
return { hello: 'world' };
});
fastify.listen({ port: 3000 });
Koa
import Koa from 'koa';
import * as Sentry from '@sentry/node';
const app = new Koa();
Sentry.init({
dsn: 'YOUR_DSN_HERE',
integrations: [Sentry.koaIntegration()],
});
app.use(Sentry.setupKoaErrorHandler(app));
app.use(async (ctx) => {
ctx.body = 'Hello World';
});
app.listen(3000);
Hapi
import Hapi from '@hapi/hapi';
import * as Sentry from '@sentry/node';
const server = Hapi.server({
port: 3000,
});
// Register Sentry plugin
await server.register(Sentry.hapiIntegration());
await Sentry.setupHapiErrorHandler(server);
server.route({
method: 'GET',
path: '/',
handler: (request, h) => {
return 'Hello World!';
},
});
await server.start();
Database Integrations
Prisma
import { PrismaClient } from '@prisma/client';
import * as Sentry from '@sentry/node';
Sentry.init({
dsn: 'YOUR_DSN_HERE',
integrations: [Sentry.prismaIntegration()],
});
const prisma = new PrismaClient();
MongoDB
import { MongoClient } from 'mongodb';
import * as Sentry from '@sentry/node';
Sentry.init({
dsn: 'YOUR_DSN_HERE',
integrations: [Sentry.mongoIntegration()],
});
// MongoDB will be automatically instrumented
const client = new MongoClient(url);
PostgreSQL
import pg from 'pg';
import * as Sentry from '@sentry/node';
Sentry.init({
dsn: 'YOUR_DSN_HERE',
integrations: [Sentry.postgresIntegration()],
});
const client = new pg.Client();
await client.connect();
Usage
Capturing Errors
import * as Sentry from '@sentry/node';
try {
someFunctionThatMightFail();
} catch (error) {
Sentry.captureException(error);
}
Capturing Messages
import * as Sentry from '@sentry/node';
Sentry.captureMessage('Something went wrong!', 'warning');
Setting Context
import * as Sentry from '@sentry/node';
// Set user
Sentry.setUser({
id: '123',
email: '[email protected]'
});
// Set tags
Sentry.setTag('service', 'api');
Sentry.setTag('environment', 'production');
// Set extra context
Sentry.setExtra('requestId', req.id);
Sentry.setContext('server', {
hostname: os.hostname(),
pid: process.pid,
});
Custom Spans
Create custom performance spans:
import * as Sentry from '@sentry/node';
const result = await Sentry.startSpan(
{
name: 'expensive-operation',
op: 'function',
},
async () => {
// Your expensive operation
return await doSomethingExpensive();
}
);
Cron Monitoring
Monitor scheduled jobs:
import * as Sentry from '@sentry/node';
const checkInId = Sentry.captureCheckIn({
monitorSlug: 'daily-backup',
status: 'in_progress',
});
try {
await performBackup();
Sentry.captureCheckIn({
checkInId,
monitorSlug: 'daily-backup',
status: 'ok',
});
} catch (error) {
Sentry.captureCheckIn({
checkInId,
monitorSlug: 'daily-backup',
status: 'error',
});
}
Or use the withMonitor helper:
import * as Sentry from '@sentry/node';
const result = await Sentry.withMonitor(
'daily-backup',
async () => {
return await performBackup();
}
);
Advanced Configuration
Environment and Release
Sentry.init({
dsn: 'YOUR_DSN_HERE',
environment: process.env.NODE_ENV,
release: process.env.RELEASE_VERSION,
});
Sampling
Sentry.init({
dsn: 'YOUR_DSN_HERE',
// Traces sampling
tracesSampleRate: 0.2, // 20% of transactions
// Or use dynamic sampling
tracesSampler: (samplingContext) => {
// Sample based on the context
if (samplingContext.transactionContext.name.includes('/health')) {
return 0; // Don't trace health checks
}
return 0.5; // 50% for everything else
},
});
Filtering Events
Sentry.init({
dsn: 'YOUR_DSN_HERE',
beforeSend(event, hint) {
// Don't send errors from specific modules
if (event.exception?.values?.[0]?.stacktrace?.frames?.some(
frame => frame.filename?.includes('node_modules')
)) {
return null;
}
return event;
},
});
Integrations
import * as Sentry from '@sentry/node';
Sentry.init({
dsn: 'YOUR_DSN_HERE',
integrations: [
// HTTP instrumentation
Sentry.httpIntegration(),
// Database integrations
Sentry.prismaIntegration(),
Sentry.mongoIntegration(),
Sentry.postgresIntegration(),
// Framework integrations
Sentry.expressIntegration(),
// Console integration
Sentry.captureConsoleIntegration({
levels: ['error'],
}),
],
});
Troubleshooting
Missing Traces
If you’re not seeing traces:
- Ensure
Sentry.init() is called before importing other modules
- Check that
tracesSampleRate is set to a value greater than 0
- For ESM, use the
--import flag
Duplicate Errors
If you’re seeing duplicate errors, make sure you’re not:
- Calling
Sentry.init() multiple times
- Manually capturing errors that are automatically captured
- Using multiple error handlers that both report to Sentry
Source Maps
For TypeScript or transpiled code:
-
Enable source maps in your
tsconfig.json:
{
"compilerOptions": {
"sourceMap": true
}
}
-
Use
Sentry.rewriteFramesIntegration() to map stack traces:
Sentry.init({
dsn: 'YOUR_DSN_HERE',
integrations: [
Sentry.rewriteFramesIntegration({
root: process.cwd(),
}),
],
});
Remember to flush events before your application exits, especially in serverless environments:await Sentry.flush(2000);
process.exit();
Next Steps