DebugBundle
SDKs

Node.js SDK

Capture exceptions, logs, HTTP context, and probes from Node.js applications. Express, Fastify, and Next.js integrations included.

Installation

npm install @debugbundle/sdk-node

Quick Setup

import DebugBundle from '@debugbundle/sdk-node';

DebugBundle.init({
  projectToken: 'local',       // 'local' for local-only, or your project token
  environment: 'production',
  service: 'my-api',
});

Calling init() automatically:

  • Hooks process.on('uncaughtException') and process.on('unhandledRejection')
  • Registers SIGINT/SIGTERM/beforeExit handlers for graceful flush
  • Auto-detects and attaches logger integrations (pino, winston, bunyan)
  • Starts remote probe config polling (connected mode, paid tiers)

Configuration

OptionTypeDefaultDescription
projectTokenstringRequired. Use 'local' for local-only mode, or your project token for connected mode. If empty, SDK is disabled.
environmentstringprocess.env.NODE_ENV ?? "development"Environment name. Controls transport selection.
servicestringAuto-detected from package.json nameService identifier. Falls back to "node-service".
frameworkstring | nullAuto-detected"express", "fastify", or "nextjs". Auto-detected from dependencies.
projectMode"connected" | "local-only""connected""local-only" uses file transport exclusively.
localEventsDirstring.debugbundle/local/eventsFile transport destination directory.
enabledbooleantrueKill switch. Set false to fully disable capture.
redactFieldsstring[]["password", "secret", "token", "authorization", "cookie", "ssn", "credit_card"]Field names to redact from captured data.
sampleRatenumber (0–1)1.0Event-level sampling rate. 0.5 = capture 50% of events.
logLevelLogLevel"warning"Minimum log level to capture: "debug", "info", "warning", "error", "critical".
batchSizenumber50Maximum events per flush batch.
flushIntervalnumber (ms)2000Auto-flush interval.
maxBufferedEventsnumber1000Maximum events in buffer. Oldest dropped when full.
endpointstring"https://api.debugbundle.com/v1/events"Ingestion API endpoint.
requestTimeoutMsnumber (ms)5000HTTP transport timeout.
captureConsolebooleanfalseOpt-in: capture console.error and console.warn.
autoDetectLoggersbooleantrueAuto-detect and attach pino/winston/bunyan on init.
loggerunknownPass an existing logger instance to attach on init.
probesPollIntervalnumber (ms)60000Remote probe config poll interval.
maxProbeLabelsnumber50Maximum distinct probe labels.
maxProbeEntriesPerLabelnumber10Ring buffer size per probe label.
probeFlushOnErrorbooleantrueFlush probe buffers alongside exceptions.
transportDebugBundleTransportAuto-selectedCustom transport override.
fetchImpltypeof fetchglobalThis.fetchCustom fetch implementation for HTTP transport.
onDiagnostic(diagnostic) => voidCallback for SDK self-diagnostic events.

Transport Selection

The SDK automatically picks the right transport:

projectModeEnvironmentTransportDestination
connectedlocal, developmentFile.debugbundle/local/events/
connectedstaging, productionHTTPPOST /v1/events
local-onlyAnyFile.debugbundle/local/events/

File transport writes atomic files: <timestamp>-<sequence>-<service>.events.json.


Framework Integrations

Express

import DebugBundle from '@debugbundle/sdk-node';
import express from 'express';

DebugBundle.init({
  projectToken: 'local',
  environment: 'production',
  service: 'my-api',
});

const app = express();

// Add DebugBundle middleware — captures request/response context
app.use(DebugBundle.express());

app.get('/api/users', (req, res) => {
  res.json({ users: [] });
});

// Error handler — DebugBundle captures the error with full request context
app.use((err, req, res, next) => {
  res.status(500).json({ error: 'Internal server error' });
});

app.listen(3000);

The Express middleware:

  • Hooks res.end() to capture request/response pairs
  • Uses runWithRequestContext() for async correlation
  • Auto-detects loggers from req.app.locals.logger, req.logger, or req.log
  • Captures exceptions passed to next(error)

Fastify

import DebugBundle from '@debugbundle/sdk-node';
import Fastify from 'fastify';

DebugBundle.init({
  projectToken: 'local',
  environment: 'production',
  service: 'my-api',
});

const app = Fastify({ logger: true });

// Register DebugBundle plugin — auto-hooks pino logger
app.register(DebugBundle.fastify());

app.get('/api/users', async (request, reply) => {
  return { users: [] };
});

app.listen({ port: 3000 });

The Fastify plugin:

  • Uses onRequest, onResponse, and onError hooks
  • Automatically hooks Fastify's built-in pino logger
  • Correlates requests via runWithRequestContext()

Next.js

// pages/api/users.ts (or app route handler)
import DebugBundle from '@debugbundle/sdk-node';

DebugBundle.init({
  projectToken: 'local',
  environment: 'production',
  service: 'my-frontend-api',
});

export default DebugBundle.nextjs(async (req, res) => {
  res.json({ users: [] });
});

The Next.js wrapper catches thrown errors and calls captureException with the full request context.


Logger Integrations

The SDK auto-detects and patches your existing logger on init(). Detection priority: pino → bunyan → winston.

pino

import pino from 'pino';
import DebugBundle from '@debugbundle/sdk-node';

const logger = pino();

DebugBundle.init({
  projectToken: 'local',
  environment: 'production',
  service: 'my-api',
  logger: logger,  // or let autoDetectLoggers find it
});

// These log calls are now captured by DebugBundle
logger.info('Server started');
logger.error({ err: new Error('fail') }, 'Request failed');

winston

import winston from 'winston';
import DebugBundle from '@debugbundle/sdk-node';

const logger = winston.createLogger({
  transports: [new winston.transports.Console()],
});

DebugBundle.init({
  projectToken: 'local',
  environment: 'production',
  service: 'my-api',
  logger: logger,
});

logger.error('Something went wrong', { userId: '123' });

bunyan

import bunyan from 'bunyan';
import DebugBundle from '@debugbundle/sdk-node';

const logger = bunyan.createLogger({ name: 'my-api' });

DebugBundle.init({
  projectToken: 'local',
  environment: 'production',
  service: 'my-api',
  logger: logger,
});

logger.error(new Error('fail'), 'Request failed');

Level mapping for all loggers:

Logger levelDebugBundle level
tracedebug
debugdebug
infoinfo
warn / warningwarning
errorerror
fatalcritical

The original logger behavior is preserved — DebugBundle patches call the original method first, then capture.


Manual Capture

Exceptions

try {
  await riskyOperation();
} catch (error) {
  DebugBundle.captureException(error, {
    request: req,
    response: res,
    tags: { component: 'payment' },
  });
}

Logs

DebugBundle.captureLog('User signup completed', 'info', {
  tags: { flow: 'onboarding' },
});

HTTP Requests

DebugBundle.captureRequest(
  { method: 'POST', url: '/api/charge', headers: req.headers, body: req.body },
  { statusCode: 500, headers: res.getHeaders(), body: responseBody },
);

Context

// This context attaches to all future events
DebugBundle.setContext('user', { id: '123', plan: 'team' });
DebugBundle.setContext('deploy', { version: '1.2.3', region: 'us-east-1' });

Probes

Probes are always-on diagnostic ring buffers. Data is captured locally and flushes alongside exceptions.

// Always-on probe — runs on every request (all tiers)
DebugBundle.probe('db-query-timing', {
  query: 'SELECT * FROM users',
  duration: 142,
  rows: 50,
});

// Lazy probe — callback only invoked when needed
DebugBundle.probe('memory-snapshot', () => ({
  heapUsed: process.memoryUsage().heapUsed,
  rss: process.memoryUsage().rss,
}));

// Heavy probe — only runs when remotely activated (paid tiers)
DebugBundle.probe('full-request-dump', () => ({
  headers: req.headers,
  body: req.body,
  timing: performanceTiming,
}), { heavy: true });

Each probe label maintains a ring buffer of the last 10 entries (configurable via maxProbeEntriesPerLabel). When an exception fires, all probe buffers are flushed alongside the error event and attach to the resulting debug bundle as context.probe_data.


Volume Control

The SDK enforces automatic storm suppression:

ControlThresholdBehavior
Duplicate dedup3 events in 30sIdentical events beyond the 3rd are suppressed
Loop detection10+ events in 2sEnters suppression mode
Suppression checkpointEvery 30sOne aggregate error_suppressed event
Auto-recovery60s silenceResets to normal capture

Combined with the server-side sampleRate and logLevel configuration, you always have layered control over event volume.


Browser Relay

The Node.js SDK includes relay handlers that proxy browser events from your frontend. See Browser Relay Setup for details.

Available as subpath exports:

// Express
import { debugBundleRelay } from '@debugbundle/sdk-node/relay/express';
app.use('/debugbundle/browser', debugBundleRelay());

// Fastify
import { debugBundleRelayPlugin } from '@debugbundle/sdk-node/relay/fastify';
app.register(debugBundleRelayPlugin);

// Next.js
import { debugBundleRelay } from '@debugbundle/sdk-node/relay/nextjs';
export const POST = debugBundleRelay;

Next Steps

  • Browser SDK — Client-side capture with breadcrumbs, network, and session controls
  • Browser Relay Setup — Configure the relay handler connecting browser → backend
  • SDKs Overview — Universal interface and language support matrix

On this page