Zero-config distributed tracing and performance monitoring for Express and NestJS applications.
- Zero Configuration - Works out of the box with sensible defaults
- Automatic Instrumentation - No code changes needed
- Express Support - Simple middleware integration
- NestJS Support - Module and interceptor-based tracing
- TypeScript First - Full type definitions included
- HTTP Request Tracing - Track every request, route, and handler
- Error Tracking - Capture exceptions with full context
- Code Monitoring - Live debugging with breakpoints and variable inspection
- Low Overhead - < 5% performance impact
npm install @tracekit/node-apmconst express = require('express');
const tracekit = require('@tracekit/node-apm');
const app = express();
// Initialize TraceKit
tracekit.init({
apiKey: process.env.TRACEKIT_API_KEY,
serviceName: 'my-express-app',
});
// Add middleware (must be before routes)
app.use(tracekit.middleware());
// Your routes
app.get('/', (req, res) => {
res.send('Hello World!');
});
app.listen(3000);import express from 'express';
import * as tracekit from '@tracekit/node-apm';
const app = express();
// Initialize TraceKit
tracekit.init({
apiKey: process.env.TRACEKIT_API_KEY!,
serviceName: 'my-express-app',
});
// Add middleware
app.use(tracekit.middleware());
// Your routes
app.get('/', (req, res) => {
res.send('Hello World!');
});
app.listen(3000);// app.module.ts
import { Module } from '@nestjs/common';
import { TracekitModule } from '@tracekit/node-apm/nestjs';
@Module({
imports: [
TracekitModule.forRoot({
apiKey: process.env.TRACEKIT_API_KEY!,
serviceName: 'my-nestjs-app',
}),
],
})
export class AppModule {}That's it! Your app is now automatically traced.
TraceKit includes production-safe code monitoring for live debugging without redeployment.
import * as tracekit from '@tracekit/node-apm';
// Enable code monitoring
const client = tracekit.init({
apiKey: process.env.TRACEKIT_API_KEY!,
serviceName: 'my-app',
enableCodeMonitoring: true, // Enable live debugging
});Add checkpoints anywhere in your code to capture variable state and stack traces:
// In any service or controller
app.post('/checkout', async (req, res) => {
const cart = req.body.cart;
const userId = req.body.userId;
// Capture snapshot at this point
await client.captureSnapshot('checkout-validation', {
userId,
cartItems: cart.items.length,
totalAmount: cart.total,
});
// Process payment...
const result = await processPayment(cart);
// Another checkpoint
await client.captureSnapshot('payment-complete', {
userId,
paymentId: result.paymentId,
success: result.success,
});
res.json(result);
});- Auto-Registration: First call to
captureSnapshot()automatically creates breakpoints in TraceKit - Smart Matching: Breakpoints match by function name + label (stable across code changes)
- Background Sync: SDK polls for active breakpoints every 30 seconds
- Production Safe: No performance impact when breakpoints are inactive
Snapshots include:
- Variables: Local variables at capture point
- Stack Trace: Full call stack with file/line numbers
- Request Context: HTTP method, URL, headers, query params
- Execution Time: When the snapshot was captured
import { Injectable, Inject } from '@nestjs/common';
import { SnapshotClient } from '@tracekit/node-apm';
@Injectable()
export class PaymentService {
constructor(
@Inject('TRACEKIT_SNAPSHOT_CLIENT')
private snapshotClient?: SnapshotClient
) {}
async processPayment(order: Order) {
// Automatic snapshot capture
await this.snapshotClient?.checkAndCaptureWithContext('payment-processing', {
orderId: order.id,
amount: order.amount,
});
// ... payment logic
}
}Get your API key at https://app.tracekit.dev
import * as tracekit from '@tracekit/node-apm';
tracekit.init({
// Required: Your TraceKit API key
apiKey: process.env.TRACEKIT_API_KEY,
// Optional: Service name (default: 'node-app')
serviceName: 'my-service',
// Optional: TraceKit endpoint (default: 'https://app.tracekit.dev/v1/traces')
endpoint: 'https://app.tracekit.dev/v1/traces',
// Optional: Enable/disable tracing (default: true)
enabled: process.env.NODE_ENV !== 'development',
// Optional: Sample rate 0.0-1.0 (default: 1.0 = 100%)
sampleRate: 0.5, // Trace 50% of requests
// Optional: Enable live code debugging (default: false)
enableCodeMonitoring: true, // Enable breakpoints and snapshots
});import { Module } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { TracekitModule } from '@tracekit/node-apm/nestjs';
@Module({
imports: [
ConfigModule.forRoot(),
TracekitModule.forRootAsync({
inject: [ConfigService],
useFactory: (config: ConfigService) => ({
apiKey: config.get('TRACEKIT_API_KEY')!,
serviceName: config.get('APP_NAME', 'my-app'),
enabled: config.get('NODE_ENV') !== 'development',
enableCodeMonitoring: config.get('TRACEKIT_CODE_MONITORING_ENABLED', false),
}),
}),
],
})
export class AppModule {}Every HTTP request is automatically traced with:
- Route path and HTTP method
- Request URL and query parameters
- HTTP status code
- Request duration
- User agent and client IP
- Controller and handler names (NestJS)
All exceptions are automatically captured with:
- Exception type and message
- Full stack trace
- Request context
- Handler information
import { getClient } from '@tracekit/node-apm';
app.get('/custom', async (req, res) => {
const client = getClient();
const span = client.startSpan('my-operation', null, {
'user.id': req.user?.id,
'custom.attribute': 'value',
});
try {
const result = await doSomething();
client.endSpan(span, {
'result.count': result.length,
});
res.json(result);
} catch (error) {
client.recordException(span, error as Error);
client.endSpan(span, {}, 'ERROR');
throw error;
}
});import { Injectable, Inject } from '@nestjs/common';
import { TracekitClient } from '@tracekit/node-apm/nestjs';
@Injectable()
export class MyService {
constructor(
@Inject('TRACEKIT_CLIENT') private tracekit: TracekitClient
) {}
async doSomething() {
const span = this.tracekit.startSpan('custom-operation', null, {
'operation.type': 'database',
});
try {
const result = await this.database.query();
this.tracekit.endSpan(span, {
'rows.count': result.length,
});
return result;
} catch (error) {
this.tracekit.recordException(span, error as Error);
this.tracekit.endSpan(span, {}, 'ERROR');
throw error;
}
}
}tracekit.init({
apiKey: process.env.TRACEKIT_API_KEY!,
enabled: process.env.NODE_ENV === 'production',
});tracekit.init({
apiKey: process.env.TRACEKIT_API_KEY!,
sampleRate: 0.1, // Trace 10% of requests
});TraceKit APM is designed to have minimal performance impact:
- < 5% overhead on average request time
- Asynchronous trace sending (doesn't block responses)
- Automatic batching and compression
- Configurable sampling for high-traffic apps
Full TypeScript support with type definitions included:
import { TracekitClient, TracekitConfig, Span } from '@tracekit/node-apm';
const config: TracekitConfig = {
apiKey: 'your-key',
serviceName: 'my-app',
};
const attributes: Record<string, any> = {
'user.id': 123,
'request.path': '/api/users',
};
// Using the client
const client = new TracekitClient(config);
const span: Span = client.startSpan('my-operation', null, attributes);- Node.js 16.x or higher
- Express 4.x or 5.x (for Express support)
- NestJS 10.x (for NestJS support)
const express = require('express');
const tracekit = require('@tracekit/node-apm');
const app = express();
tracekit.init({
apiKey: process.env.TRACEKIT_API_KEY,
serviceName: 'express-example',
});
app.use(tracekit.middleware());
app.get('/users', async (req, res) => {
const users = await db.getUsers();
res.json(users);
});
app.listen(3000);// main.ts
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
await app.listen(3000);
}
bootstrap();
// app.module.ts
import { Module } from '@nestjs/common';
import { TracekitModule } from '@tracekit/node-apm/nestjs';
import { UsersModule } from './users/users.module';
@Module({
imports: [
TracekitModule.forRoot({
apiKey: process.env.TRACEKIT_API_KEY!,
serviceName: 'nestjs-example',
}),
UsersModule,
],
})
export class AppModule {}
// users.controller.ts
import { Controller, Get } from '@nestjs/common';
import { UsersService } from './users.service';
@Controller('users')
export class UsersController {
constructor(private usersService: UsersService) {}
@Get()
findAll() {
return this.usersService.findAll();
}
}- Documentation: https://app.tracekit.dev/docs
- Issues: https://github.com/Tracekit-Dev/node-apm/issues
- Email: support@tracekit.dev
MIT License. See LICENSE for details.
Built with ❤️ by the TraceKit team.