Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Full Sentry SDK setup for Node.js, Bun, and Deno. Use when asked to \"add Sentry to Node.js\", \"add Sentry to Bun\", \"add Sentry to Deno\", \"install @sentry/node\", \"@sentry/bun\", or \"@sentry/deno\", or configure error monitoring, tracing, logging, profiling, metrics, crons, or AI monitoring for server-side JavaScript/TypeScript runtimes.
.claude/skills/kunanonj-cursor-plugin-sentry-sentry-node-sdk/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-02 | ✗→✓ | ▲ Improved | 378% | 0% |
| case-03 | ✗→✓ | ▲ Improved | 283% | 0% |
| case-05 | ✗→✓ | ▲ Improved | 350% | 0% |
| case-06 | ✗→✓ | ▲ Improved | 583% | 0% |
| case-07 | ✗→✓ | ▲ Improved | 243% | 0% |
> All Skills > SDK Setup > Node.js / Bun / Deno SDK
Opinionated wizard that scans your project and guides you through complete Sentry setup for server-side JavaScript and TypeScript runtimes: Node.js, Bun, and Deno.
@sentry/node, @sentry/bun, or @sentry/denoinstrument.js, --import ./instrument.mjs, bun --preload, or npm:@sentry/deno> NestJS? Use sentry-nestjs-sdk instead — it uses @sentry/nestjs with NestJS-native decorators and filters. > Next.js? Use sentry-nextjs-sdk instead — it handles the three-runtime architecture (browser, server, edge).
> Note: SDK versions below reflect current Sentry docs at time of writing (@sentry/node ≥10.42.0, @sentry/bun ≥10.42.0, @sentry/deno ≥10.42.0). > Always verify against docs.sentry.io/platforms/javascript/guides/node/ before implementing.
Run these commands to identify the runtime, framework, and existing Sentry setup:
bash# Detect runtime bun --version 2>/dev/null && echo "Bun detected" deno --version 2>/dev/null && echo "Deno detected" node --version 2>/dev/null && echo "Node.js detected" # Detect existing Sentry packages cat package.json 2>/dev/null | grep -E '"@sentry/' cat deno.json deno.jsonc 2>/dev/null | grep -i sentry # Detect Node.js framework cat package.json 2>/dev/null | grep -E '"express"|"fastify"|"@hapi/hapi"|"koa"|"@nestjs/core"|"connect"' # Detect Bun-specific frameworks cat package.json 2>/dev/null | grep -E '"elysia"|"hono"' # Detect Deno frameworks (deno.json imports) cat deno.json deno.jsonc 2>/dev/null | grep -E '"oak"|"hono"|"fresh"' # Detect module system (Node.js) cat package.json 2>/dev/null | grep '"type"' ls *.mjs *.cjs 2>/dev/null | head -5 # Detect existing instrument file ls instrument.js instrument.mjs instrument.ts instrument.cjs 2>/dev/null # Detect logging libraries cat package.json 2>/dev/null | grep -E '"winston"|"pino"|"bunyan"' # Detect cron / scheduling cat package.json 2>/dev/null | grep -E '"node-cron"|"cron"|"agenda"|"bull"|"bullmq"' # Detect AI / LLM usage cat package.json 2>/dev/null | grep -E '"openai"|"@anthropic-ai"|"@langchain"|"@vercel/ai"|"@google/generative-ai"' # Detect OpenTelemetry tracing cat package.json 2>/dev/null | grep -E '"@opentelemetry/sdk-node"|"@opentelemetry/sdk-trace-node"|"@opentelemetry/sdk-trace-base"' grep -rn "NodeTracerProvider\|trace\.getTracer\|startActiveSpan" \ --include="*.ts" --include="*.js" --include="*.mjs" 2>/dev/null | head -5 # Check for companion frontend ls frontend/ web/ client/ ui/ 2>/dev/null cat package.json 2>/dev/null | grep -E '"react"|"vue"|"svelte"|"next"'
What to determine:
| Question | Impact | |----------|--------| | Which runtime? (Node.js / Bun / Deno) | Determines package, init pattern, and preload flag | | Node.js: ESM or CJS? | ESM requires --import ./instrument.mjs; CJS uses require("./instrument") | | Framework detected? | Determines which error handler to register | | @sentry/* already installed? | Skip install, go straight to feature config | | instrument.js / instrument.mjs already exists? | Merge into it rather than overwrite | | Logging library detected? | Recommend Sentry Logs | | Cron / job scheduler detected? | Recommend Crons monitoring | | AI library detected? | Recommend AI Monitoring | | OpenTelemetry tracing detected? | Use OTLP path instead of native tracing | | Companion frontend found? | Trigger Phase 4 cross-link |
Present a concrete recommendation based on what you found. Don't ask open-ended questions — lead with a proposal:
Route from OTel detection:
@opentelemetry/sdk-node or @opentelemetry/sdk-trace-node in package.json, or NodeTracerProvider in source) → use OTLP path: otlpIntegration() via @sentry/node-core/light; do not set tracesSampleRate; Sentry links errors to OTel traces automaticallyRecommended (core coverage):
Optional (enhanced observability):
Sentry.logger.*; recommend when winston/pino/bunyan or log search is needednodeRuntimeMetricsIntegration() (Node.js) / bunRuntimeMetricsIntegration() (Bun)Recommendation logic:
| Feature | Recommend when... | |---------|------------------| | Error Monitoring | Always — non-negotiable baseline | | OTLP Integration | OTel tracing detected — replaces native Tracing | | Tracing | Always for server apps — HTTP spans + DB spans are high-value; skip if OTel tracing detected | | Logging | App uses winston, pino, bunyan, or needs log-to-trace correlation | | Profiling | Node.js only — performance-critical service; native addon compatible; skip if OTel tracing detected (requires tracesSampleRate, incompatible with OTLP) | | AI Monitoring | App calls OpenAI, Anthropic, LangChain, Vercel AI, or Google GenAI | | Crons | App uses node-cron, Bull, BullMQ, Agenda, or any scheduled task pattern | | Metrics | App needs custom counters, gauges, or histograms | | Runtime Metrics | Any Node.js or Bun service wanting automatic memory/CPU/event-loop visibility |
OTel tracing detected: "I see OpenTelemetry tracing in the project. I recommend Sentry's OTLP integration for tracing (via your existing OTel setup) + Error Monitoring + Sentry Logging [+ Metrics/Crons/AI Monitoring if applicable]. Shall I proceed?"
No OTel: "I recommend setting up Error Monitoring + Tracing. Want me to also add Logging or Profiling?"
> You need to run this yourself — the wizard opens a browser for login and requires interactive input that the agent can't handle. Copy-paste into your terminal: > > > npx @sentry/wizard@latest -i node > > > It handles login, org/project selection, SDK installation, instrument.js creation, and package.json script updates. > > Once it finishes, come back and skip to Verification.
If the user skips the wizard, proceed with Option 2 (Manual Setup) below.
##### Install
bashnpm install @sentry/node --save # or yarn add @sentry/node # or pnpm add @sentry/node
##### Create the Instrument File
CommonJS (instrument.js):
javascript// instrument.js — must be loaded before all other modules const Sentry = require("@sentry/node"); Sentry.init({ dsn: process.env.SENTRY_DSN ?? "___DSN___", sendDefaultPii: true, // 100% in dev, lower in production tracesSampleRate: process.env.NODE_ENV === "development" ? 1.0 : 0.1, // Capture local variable values in stack frames includeLocalVariables: true, enableLogs: true, });
ESM (instrument.mjs):
javascript// instrument.mjs — loaded via --import flag before any other module import * as Sentry from "@sentry/node"; Sentry.init({ dsn: process.env.SENTRY_DSN ?? "___DSN___", sendDefaultPii: true, tracesSampleRate: process.env.NODE_ENV === "development" ? 1.0 : 0.1, includeLocalVariables: true, enableLogs: true, });
##### Start Your App with Sentry Loaded First
CommonJS — add require("./instrument") as the very first line of your entry file:
javascript// app.js require("./instrument"); // must be first const express = require("express"); // ... rest of your app
ESM — use the --import flag so Sentry loads before all other modules (Node.js 18.19.0+ required):
bashnode --import ./instrument.mjs app.mjs
Add to package.json scripts:
json{ "scripts": { "start": "node --import ./instrument.mjs server.mjs", "dev": "node --import ./instrument.mjs --watch server.mjs" } }
Or via environment variable (useful for wrapping existing start commands):
bashNODE_OPTIONS="--import ./instrument.mjs" npm start
##### Framework Error Handlers
Register the Sentry error handler after all routes so it can capture framework errors:
Express:
javascriptconst express = require("express"); const Sentry = require("@sentry/node"); const app = express(); // ... your routes // Add AFTER all routes — captures 5xx errors by default Sentry.setupExpressErrorHandler(app); // Optional: capture 4xx errors too // Sentry.setupExpressErrorHandler(app, { // shouldHandleError(error) { return error.status >= 400; }, // }); app.listen(3000);
Fastify:
javascriptconst Fastify = require("fastify"); const Sentry = require("@sentry/node"); const fastify = Fastify(); // Add BEFORE routes (unlike Express!) Sentry.setupFastifyErrorHandler(fastify); // ... your routes await fastify.listen({ port: 3000 });
Koa:
javascriptconst Koa = require("koa"); const Sentry = require("@sentry/node"); const app = new Koa(); // Add as FIRST middleware (catches errors thrown by later middleware) Sentry.setupKoaErrorHandler(app); // ... your other middleware and routes app.listen(3000);
Hapi (async — must await):
javascriptconst Hapi = require("@hapi/hapi"); const Sentry = require("@sentry/node"); const server = Hapi.server({ port: 3000 }); // ... your routes // Must await — Hapi registration is async await Sentry.setupHapiErrorHandler(server); await server.start();
Connect:
javascriptconst connect = require("connect"); const Sentry = require("@sentry/node"); const app = connect(); // Add BEFORE routes (like Fastify and Koa) Sentry.setupConnectErrorHandler(app); // ... your middleware and routes require("http").createServer(app).listen(3000);
NestJS — has its own dedicated skill with full coverage:
> Use the sentry-nestjs-sdk skill instead. > NestJS uses a separate package (@sentry/nestjs) with NestJS-native constructs: > SentryModule.forRoot(), SentryGlobalFilter, @SentryTraced, @SentryCron decorators, > and GraphQL/Microservices support. Load that skill for complete NestJS setup.
Vanilla Node.js http module — wrap request handler manually:
javascriptconst http = require("http"); const Sentry = require("@sentry/node"); const server = http.createServer((req, res) => { Sentry.withIsolationScope(() => { try { // your handler res.end("OK"); } catch (err) { Sentry.captureException(err); res.writeHead(500); res.end("Internal Server Error"); } }); }); server.listen(3000);
Framework error handler summary:
| Framework | Function | Placement | Async? | |-----------|----------|-----------|--------| | Express | setupExpressErrorHandler(app) | After all routes | No | | Fastify | setupFastifyErrorHandler(fastify) | Before routes | No | | Koa | setupKoaErrorHandler(app) | First middleware | No | | Hapi | setupHapiErrorHandler(server) | Before server.start() | Yes | | Connect | setupConnectErrorHandler(app) | Before routes | No | | NestJS | → Use sentry-nestjs-sdk | Dedicated skill | — |
> No wizard available for Bun. Manual setup only.
bashbun add @sentry/bun
instrument.ts (or instrument.js)typescript// instrument.ts import * as Sentry from "@sentry/bun"; Sentry.init({ dsn: process.env.SENTRY_DSN ?? "___DSN___", sendDefaultPii: true, tracesSampleRate: process.env.NODE_ENV === "development" ? 1.0 : 0.1, enableLogs: true, });
--preloadbashbun --preload ./instrument.ts server.ts
Add to package.json:
json{ "scripts": { "start": "bun --preload ./instrument.ts server.ts", "dev": "bun --watch --preload ./instrument.ts server.ts" } }
@sentry/bun automatically instruments Bun.serve() via JavaScript Proxy. No extra setup is required — just initialize with --preload and your Bun.serve() calls are traced:
typescript// server.ts const server = Bun.serve({ port: 3000, fetch(req) { return new Response("Hello from Bun!"); }, });
Bun can run Express, Fastify, Hono, and Elysia. Use the same @sentry/bun import and the @sentry/node error handler functions (re-exported by @sentry/bun):
typescriptimport * as Sentry from "@sentry/bun"; import express from "express"; const app = express(); // ... routes Sentry.setupExpressErrorHandler(app); app.listen(3000);
| Feature | Bun Support | Notes | |---------|-------------|-------| | Error Monitoring | ✅ Full | Same API as Node | | Tracing | ✅ Via @sentry/node OTel | Most auto-instrumentations work | | Logging | ✅ Full | enableLogs: true + Sentry.logger.* | | Profiling | ❌ Not available | @sentry/profiling-node uses native addons incompatible with Bun | | Metrics | ✅ Full | Sentry.metrics.* | | Runtime Metrics | ✅ Full | bunRuntimeMetricsIntegration() — memory, CPU, event loop (no event loop delay percentiles) | | Crons | ✅ Full | Sentry.withMonitor() | | AI Monitoring | ✅ Full | OpenAI, Anthropic integrations work |
> No wizard available for Deno. Manual setup only. > Requires Deno 2.0+. Deno 1.x is not supported. > Use npm: specifier. The deno.land/x/sentry registry is deprecated.
deno.json (Recommended)json{ "imports": { "@sentry/deno": "npm:@sentry/deno@10.42.0" } }
Or import directly with the npm: specifier:
typescriptimport * as Sentry from "npm:@sentry/deno";
typescript// main.ts — Sentry.init() must be called before any other code import * as Sentry from "@sentry/deno"; Sentry.init({ dsn: Deno.env.get("SENTRY_DSN") ?? "___DSN___", sendDefaultPii: true, tracesSampleRate: Deno.env.get("DENO_ENV") === "development" ? 1.0 : 0.1, enableLogs: true, }); // Your application code follows Deno.serve({ port: 8000 }, (req) => { return new Response("Hello from Deno!"); });
> Unlike Node.js and Bun, Deno does not have a --preload or --import flag. Sentry must be the first import in your entry file.
The SDK requires network access to reach your Sentry ingest domain:
bashdeno run \ --allow-net=o<ORG_ID>.ingest.sentry.io \ --allow-read=./src \ --allow-env=SENTRY_DSN,SENTRY_RELEASE \ main.ts
For development, --allow-all works but is not recommended for production.
Deno provides native cron scheduling. Use denoCronIntegration for automatic monitoring:
typescriptimport * as Sentry from "@sentry/deno"; import { denoCronIntegration } from "@sentry/deno"; Sentry.init({ dsn: Deno.env.get("SENTRY_DSN") ?? "___DSN___", integrations: [denoCronIntegration()], }); // Cron is automatically monitored Deno.cron("daily-cleanup", "0 0 * * *", () => { // cleanup logic });
| Feature | Deno Support | Notes | |---------|-------------|-------| | Error Monitoring | ✅ Full | Unhandled exceptions + captureException | | Tracing | ✅ Custom OTel | Automatic spans for Deno.serve() and fetch | | Logging | ✅ Full | enableLogs: true + Sentry.logger.* | | Profiling | ❌ Not available | No profiling addon for Deno | | Metrics | ✅ Full | Sentry.metrics.* | | Runtime Metrics | ❌ Not available | No runtime metrics integration for Deno | | Crons | ✅ Full | denoCronIntegration() + Sentry.withMonitor() | | AI Monitoring | ✅ Partial | Vercel AI SDK integration works; OpenAI/Anthropic via npm: |
> Use this path only when OpenTelemetry tracing was detected in Phase 1 > (e.g., @opentelemetry/sdk-node or @opentelemetry/sdk-trace-node in package.json). > For projects without an existing OTel setup, use the standard @sentry/node path above.
The OTLP integration uses @sentry/node-core/light — a lightweight Sentry SDK that does not bundle its own OpenTelemetry. Instead, it hooks into the user's existing OTel TracerProvider and exports spans to Sentry via OTLP.
| Scenario | Recommended path | |----------|-----------------| | New project, no existing OTel | Standard @sentry/node (above) — includes built-in OTel | | Existing OTel setup, want Sentry tracing | @sentry/node-core/light + otlpIntegration() | | Existing OTel setup, sending to own Collector | @sentry/node-core/light + otlpIntegration({ collectorUrl }) |
bashnpm install @sentry/node-core @opentelemetry/api @opentelemetry/sdk-trace-node @opentelemetry/sdk-trace-base # or yarn add @sentry/node-core @opentelemetry/api @opentelemetry/sdk-trace-node @opentelemetry/sdk-trace-base # or pnpm add @sentry/node-core @opentelemetry/api @opentelemetry/sdk-trace-node @opentelemetry/sdk-trace-base
> The @opentelemetry/* packages are peer dependencies. If the project already has them installed, skip duplicates.
javascript// instrument.mjs — load via --import flag before any other module import { NodeTracerProvider } from '@opentelemetry/sdk-trace-node'; import * as Sentry from '@sentry/node-core/light'; import { otlpIntegration } from '@sentry/node-core/light/otlp'; // Register the user's OTel TracerProvider first const provider = new NodeTracerProvider(); provider.register(); Sentry.init({ dsn: process.env.SENTRY_DSN ?? '___DSN___', sendDefaultPii: true, enableLogs: true, // Do NOT set tracesSampleRate — OTel controls sampling integrations: [ otlpIntegration({ // Export OTel spans to Sentry via OTLP (default: true) setupOtlpTracesExporter: true, }), ], });
With a custom Collector endpoint:
javascriptSentry.init({ dsn: process.env.SENTRY_DSN ?? '___DSN___', integrations: [ otlpIntegration({ collectorUrl: 'http://localhost:4318/v1/traces', }), ], });
Same --import pattern as the standard Node.js setup:
bashnode --import ./instrument.mjs app.mjs
@sentry/node| Aspect | @sentry/node (standard) | @sentry/node-core/light (OTLP) | |--------|--------------------------|----------------------------------| | OTel bundled | ✅ Yes — built-in TracerProvider | ❌ No — uses your existing provider | | Tracing control | tracesSampleRate in Sentry.init() | OTel SDK controls sampling | | Auto-instrumentation | ✅ Built-in (HTTP, DB, etc.) | ❌ You manage OTel instrumentations | | Profiling | ✅ Available | ❌ Not compatible | | Error ↔ trace linking | ✅ Automatic | ✅ Automatic (via otlpIntegration) | | Package size | Larger (includes OTel) | Smaller (light mode) |
Load the corresponding reference file and follow its steps:
| Feature | Reference file | Load when... | |---------|---------------|-------------| | Error Monitoring | references/error-monitoring.md | Always (baseline) — captures, scopes, enrichment, beforeSend | | OTLP Integration | See OTLP Integration above | OTel tracing detected — replaces native Tracing | | Tracing | references/tracing.md | OTel auto-instrumentation, custom spans, distributed tracing, sampling; skip if OTel tracing detected | | Logging | references/logging.md | Structured logs, Sentry.logger.*, log-to-trace correlation | | Profiling | references/profiling.md | Node.js only — CPU profiling, Bun/Deno gaps documented; skip if OTel tracing detected | | Metrics | references/metrics.md | Custom counters, gauges, distributions | | Runtime Metrics | See inline below | Automatic memory, CPU, and event loop metrics for Node.js and Bun | | Crons | references/crons.md | Scheduled job monitoring, node-cron, Bull, Agenda, Deno.cron | | AI Monitoring | Load sentry-setup-ai-monitoring skill | OpenAI, Anthropic, LangChain, Vercel AI, Google GenAI |
For each feature: read the reference file, follow its steps exactly, and verify before moving on.
Automatically collect Node.js and Bun runtime health metrics (memory, CPU utilization, event loop delay/utilization, uptime) at a configurable interval. Metrics appear in Sentry's Metrics product under the node.runtime.* / bun.runtime.* namespace.
Node.js — add nodeRuntimeMetricsIntegration() to your instrument.js:
javascriptconst Sentry = require("@sentry/node"); Sentry.init({ dsn: process.env.SENTRY_DSN, integrations: [ Sentry.nodeRuntimeMetricsIntegration(), // Optional: change collection interval (default 30 000 ms) // Sentry.nodeRuntimeMetricsIntegration({ collectionIntervalMs: 60_000 }), ], });
Metrics collected by default: node.runtime.mem.rss, node.runtime.mem.heap_used, node.runtime.mem.heap_total, node.runtime.cpu.utilization, node.runtime.event_loop.delay.p50, node.runtime.event_loop.delay.p99, node.runtime.event_loop.utilization, node.runtime.process.uptime.
Bun — add bunRuntimeMetricsIntegration() to your instrument.ts:
typescriptimport * as Sentry from "@sentry/bun"; import { bunRuntimeMetricsIntegration } from "@sentry/bun"; Sentry.init({ dsn: process.env.SENTRY_DSN, integrations: [ bunRuntimeMetricsIntegration(), // Optional: change collection interval (default 30 000 ms) // bunRuntimeMetricsIntegration({ collectionIntervalMs: 60_000 }), ], });
Metrics collected: same as Node.js except no event loop delay percentiles (unavailable in Bun). Prefixed with bun.runtime.*.
After setup, verify Sentry is receiving events:
javascript// Add temporarily to your entry file or a test route, then remove import * as Sentry from "@sentry/node"; // or @sentry/bun / @sentry/deno Sentry.captureException(new Error("Sentry test error — delete me"));
Or trigger an unhandled exception:
javascript// In a route handler or startup — will be captured automatically throw new Error("Sentry test error — delete me");
Then check your Sentry Issues dashboard — the error should appear within ~30 seconds.
Verification checklist:
| Check | How | |-------|-----| | Error captured | Throw in a handler, verify in Sentry Issues | | Tracing working | Check Performance tab — should show HTTP spans | | includeLocalVariables working | Stack frame in Sentry should show variable values | | Source maps working | Stack trace shows readable file names, not minified |
Sentry.init() Core Options| Option | Type | Default | Notes | |--------|------|---------|-------| | dsn | string | — | Required. Also from SENTRY_DSN env var | | tracesSampleRate | number | — | 0–1; required to enable tracing; do not set when using OTLP path | | sendDefaultPii | boolean | false | Include IP, request headers, user info | | includeLocalVariables | boolean | false | Add local variable values to stack frames (Node.js) | | enableLogs | boolean | false | Enable Sentry Logs product (v9.41.0+) | | environment | string | "production" | Also from SENTRY_ENVIRONMENT env var | | release | string | — | Also from SENTRY_RELEASE env var | | debug | boolean | false | Log SDK activity to console | | enabled | boolean | true | Set false in tests to disable sending | | sampleRate | number | 1.0 | Fraction of error events to send (0–1) | | shutdownTimeout | number | 2000 | Milliseconds to flush events before process exit |
nativeNodeFetchIntegration() OptionsConfigures outgoing fetch/undici span capture. Since @opentelemetry/instrumentation-undici@0.22.0, response headers like content-length are no longer captured automatically — use headersToSpanAttributes to opt in:
javascriptSentry.init({ integrations: [ Sentry.nativeNodeFetchIntegration({ headersToSpanAttributes: { requestHeaders: ["x-request-id"], responseHeaders: ["content-length", "content-type"], }, }), ], });
| Option | Type | Default | Notes | |--------|------|---------|-------| | breadcrumbs | boolean | true | Record breadcrumbs for outgoing fetch requests | | headersToSpanAttributes.requestHeaders | string[] | — | Request header names to capture as span attributes | | headersToSpanAttributes.responseHeaders | string[] | — | Response header names to capture as span attributes |
otlpIntegration() Options (@sentry/node-core/light/otlp)For OTel-first projects using @sentry/node-core/light. Import: import { otlpIntegration } from '@sentry/node-core/light/otlp'.
| Option | Type | Default | Purpose | |--------|------|---------|---------| | setupOtlpTracesExporter | boolean | true | Auto-configure OTLP exporter to send spans to Sentry; set false if you already export to your own Collector | | collectorUrl | string | undefined | OTLP HTTP endpoint of an OTel Collector (e.g., http://localhost:4318/v1/traces); when set, spans are sent to the collector instead of the DSN-derived Sentry endpoint |
Flush buffered events before process exit — important for short-lived scripts and serverless:
javascriptprocess.on("SIGTERM", async () => { await Sentry.close(2000); // flush with 2s timeout process.exit(0); });
| Variable | Purpose | Runtime | |----------|---------|---------| | SENTRY_DSN | DSN (alternative to hardcoding in init()) | All | | SENTRY_ENVIRONMENT | Deployment environment | All | | SENTRY_RELEASE | Release version string (auto-detected from git) | All | | SENTRY_AUTH_TOKEN | Source map upload token | Build time | | SENTRY_ORG | Org slug for source map upload | Build time | | SENTRY_PROJECT | Project slug for source map upload | Build time | | NODE_OPTIONS | Set --import ./instrument.mjs for ESM | Node.js |
Readable stack traces in production require source map upload. Use @sentry/cli or the webpack/esbuild/rollup plugins:
bashnpm install @sentry/cli --save-dev
bash# Create a Sentry auth token at sentry.io/settings/auth-tokens/ # Set in .env.sentry-build-plugin (gitignore this file): SENTRY_AUTH_TOKEN=sntrys_eyJ...
Add upload step to your build:
json{ "scripts": { "build": "tsc && sentry-cli sourcemaps inject ./dist && sentry-cli sourcemaps upload ./dist" } }
After completing backend setup, check for companion services:
bash# Frontend companion ls frontend/ web/ client/ ui/ 2>/dev/null cat package.json 2>/dev/null | grep -E '"react"|"vue"|"svelte"|"next"' # Other backend services ls ../go.mod ../requirements.txt ../Gemfile 2>/dev/null
If a frontend, framework-specific SDK, or other backend is found, suggest the matching skill:
Dedicated JavaScript framework skills (prefer these over generic node-sdk):
| Detected | Prefer skill | Why | |----------|-------------|-----| | NestJS (@nestjs/core in package.json) | sentry-nestjs-sdk | Uses @sentry/nestjs with NestJS-native decorators, filters, and GraphQL support | | Next.js (next in package.json) | sentry-nextjs-sdk | Three-runtime architecture (browser, server, edge), withSentryConfig, source map upload |
Frontend companions:
| Detected | Suggest | |---------|---------| | React app (react in package.json) | sentry-react-sdk | | Svelte/SvelteKit | sentry-svelte-sdk |
Other backend companions:
| Detected | Suggest | |---------|---------| | Go backend (go.mod) | sentry-go-sdk | | Python backend (requirements.txt, pyproject.toml) | sentry-python-sdk | | Ruby backend (Gemfile) | sentry-ruby-sdk |
Connecting frontend and backend with the same DSN or linked projects enables distributed tracing — stack traces that span your browser, API server, and database in a single trace view.
| Issue | Cause | Solution | |-------|-------|----------| | Events not appearing | instrument.js loaded too late | Ensure it's the first require() / loaded via --import or --preload | | Tracing spans missing | tracesSampleRate not set | Add tracesSampleRate: 1.0 to Sentry.init() | | ESM instrumentation not working | Missing --import flag | Run with node --import ./instrument.mjs; import "./instrument.mjs" inside app is not sufficient | | @sentry/profiling-node install fails on Bun | Native addon incompatible | Profiling is not supported on Bun — remove @sentry/profiling-node | | Deno: events not sent | Missing --allow-net permission | Run with --allow-net=o<ORG_ID>.ingest.sentry.io | | Deno: deno.land/x/sentry not working | Deprecated and frozen at v8.55.0 | Switch to npm:@sentry/deno specifier | | includeLocalVariables not showing values | Integration not activated or minified code | Ensure includeLocalVariables: true in init; check source maps | | NestJS: errors not captured | Wrong SDK or missing filter | Use sentry-nestjs-sdk — NestJS needs @sentry/nestjs, not @sentry/node | | Hapi: setupHapiErrorHandler timing issue | Not awaited | Must await Sentry.setupHapiErrorHandler(server) before server.start() | | Shutdown: events lost | Process exits before flush | Add await Sentry.close(2000) in SIGTERM/SIGINT handler | | Stack traces show minified code | Source maps not uploaded | Configure @sentry/cli source map upload in build step | | No traces appearing (OTLP) | Missing @opentelemetry/* packages or otlpIntegration not added | Verify @opentelemetry/sdk-trace-node is installed; add otlpIntegration() to integrations; do not set tracesSampleRate | | OTLP: errors not linked to traces | otlpIntegration not registered | Ensure otlpIntegration() is in the integrations array — it registers the propagation context that links errors to OTel traces | | Profiling not starting (OTLP) | Profiling requires tracesSampleRate | Profiling is not compatible with the OTLP path; use the standard @sentry/node setup instead |
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-02 | fail→pass | 10,742 | 7,485 | -30% | 1 | 1 | 0% | 2,251 | 10,765 | +378% | 0 | 0 | — |
case-22 | pass→pass | 13,467 | 16,287 | +21% | 1 | 1 | 0% | 2,769 | 12,758 | +361% | 0 | 0 | — |
case-01 | fail→fail | 9,819 | 6,565 | -33% | 1 | 1 | 0% | 2,047 | 10,559 | +416% | 0 | 0 | — |
case-03 | fail→pass | 13,765 | 9,018 | -34% | 1 | 1 | 0% | 2,890 | 11,073 | +283% | 0 | 0 | — |
case-04 | pass→pass | 9,019 | 3,251 | -64% | 1 | 1 | 0% | 1,741 | 9,853 | +466% | 0 | 0 | — |
case-05 | fail→pass | 11,249 | 3,740 | -67% | 1 | 1 | 0% | 2,217 | 9,983 | +350% | 0 | 0 | — |
case-06 | fail→pass | 7,553 | 4,898 | -35% | 1 | 1 | 0% | 1,449 | 9,902 | +583% | 0 | 0 | — |
case-07 | fail→pass | 16,529 | 7,214 | -56% | 1 | 1 | 0% | 3,100 | 10,630 | +243% | 0 | 0 | — |
case-08 | fail→pass | 13,191 | 6,837 | -48% | 1 | 1 | 0% | 2,574 | 10,648 | +314% | 0 | 0 | — |
case-09 | pass→pass | 11,170 | 5,891 | -47% | 1 | 1 | 0% | 1,945 | 10,260 | +428% | 0 | 0 | — |
case-10 | fail→pass | 13,005 | 5,042 | -61% | 1 | 1 | 0% | 2,760 | 10,281 | +273% | 0 | 0 | — |
case-11 | fail→pass | 15,307 | 4,780 | -69% | 1 | 1 | 0% | 3,222 | 10,181 | +216% | 0 | 0 | — |
case-12 | pass→pass | 7,161 | 5,322 | -26% | 1 | 1 | 0% | 1,485 | 10,320 | +595% | 0 | 0 | — |
case-13 | pass→pass | 10,911 | 7,815 | -28% | 1 | 1 | 0% | 2,156 | 10,868 | +404% | 0 | 0 | — |
case-14 | fail→pass | 17,727 | 4,706 | -73% | 1 | 1 | 0% | 3,545 | 10,248 | +189% | 0 | 0 | — |
case-15 | pass→pass | 13,198 | 6,939 | -47% | 1 | 1 | 0% | 2,558 | 10,530 | +312% | 0 | 0 | — |
case-16 | pass→pass | 10,164 | 6,809 | -33% | 1 | 1 | 0% | 1,904 | 10,495 | +451% | 0 | 0 | — |
case-17 | pass→pass | 9,782 | 6,645 | -32% | 1 | 1 | 0% | 1,909 | 10,566 | +453% | 0 | 0 | — |
case-18 | fail→pass | 7,410 | 3,462 | -53% | 1 | 1 | 0% | 1,346 | 9,811 | +629% | 0 | 0 | — |
case-19 | fail→pass | 14,908 | 5,199 | -65% | 1 | 1 | 0% | 3,064 | 10,281 | +236% | 0 | 0 | — |
case-20 | fail→pass | 13,085 | 10,876 | -17% | 1 | 1 | 0% | 2,763 | 11,553 | +318% | 0 | 0 | — |
case-21 | pass→pass | 16,190 | 15,194 | -6% | 1 | 1 | 0% | 3,140 | 12,702 | +305% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted. The headline lift of +55 percentage points is the difference between those two pass rates over the 22 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.