OpenTelemetry for Node.js
OpenTelemetry for Node.js supports zero-code instrumentation through a single --require flag (or NODE_OPTIONS) — it auto-wires HTTP, Express, Fastify, Koa, MongoDB, Postgres, MySQL, Redis, gRPC, and most other popular libraries on startup. Traces ship to CodeXray over OTLP.
Zero-code (recommended for most apps) — install one package, prepend a --require flag to your start command, set four env vars. No source changes.
Programmatic — if you need fine control or you're shipping a Next.js / NestJS / similar framework with a custom bootstrap, instantiate the SDK in code. See the Next.js doc for the framework-specific path.
Before You Begin
You'll need:
- A Node.js application (Node.js 18+)
- The URL of your CodeXray collector (e.g.,
https://your-codexray.example.com) - A project API key from the CodeXray UI (Project Settings → API Keys)
Step 1 — Install the OpenTelemetry Packages
npm install \
@opentelemetry/api \
@opentelemetry/auto-instrumentations-node \
@opentelemetry/exporter-trace-otlp-proto
| Package | What it does |
|---|---|
@opentelemetry/api | The core OTel API — used by libraries and your own code to create spans |
@opentelemetry/auto-instrumentations-node | Bundle of every auto-instrumentation library (HTTP, Express, Fastify, Postgres, MongoDB, Redis, …). Picks the ones that match what your app imports. |
@opentelemetry/exporter-trace-otlp-proto | OTLP HTTP/protobuf exporter — ships spans to your CodeXray collector |
Step 2 — Configure via Environment Variables
export OTEL_SERVICE_NAME="your-service-name"
export OTEL_EXPORTER_OTLP_ENDPOINT="https://your-codexray.example.com"
export OTEL_EXPORTER_OTLP_PROTOCOL="http/protobuf"
export OTEL_EXPORTER_OTLP_HEADERS="x-api-key=your-project-api-key"
export OTEL_TRACES_EXPORTER="otlp"
export OTEL_METRICS_EXPORTER="none"
export OTEL_LOGS_EXPORTER="none"
| Variable | Purpose |
|---|---|
OTEL_SERVICE_NAME | The name that appears in CodeXray's Applications list |
OTEL_EXPORTER_OTLP_ENDPOINT | Your CodeXray collector URL (no trailing slash) |
OTEL_EXPORTER_OTLP_PROTOCOL | http/protobuf (recommended) or grpc |
OTEL_EXPORTER_OTLP_HEADERS | Authentication — your project API key as x-api-key |
OTEL_RESOURCE_ATTRIBUTES | Optional — deployment.environment=production,service.version=1.3.0 |
Step 3 — Run with Auto-Instrumentation
Prepend --require @opentelemetry/auto-instrumentations-node/register to your start command:
node --require @opentelemetry/auto-instrumentations-node/register server.js
For npm scripts, update package.json:
{
"scripts": {
"start": "node --require @opentelemetry/auto-instrumentations-node/register server.js"
}
}
Using NODE_OPTIONS instead of --require
If you can't change the start command (PaaS, hosted runtimes), set the same thing via env:
export NODE_OPTIONS="--require @opentelemetry/auto-instrumentations-node/register"
node server.js # picks it up automatically
NODE_OPTIONS is the right choice for Docker images where the CMD is fixed and you only control env vars.
What Gets Instrumented Automatically
The auto-instrumentations-node bundle includes coverage for the most common libraries — and the SDK only activates the ones your app actually imports:
| Layer | Libraries covered |
|---|---|
| HTTP servers | http, https, express, fastify, koa, hapi, restify |
| HTTP clients | http, https, axios, undici (Node 18+ fetch), got |
| Databases | pg, mysql, mysql2, mongodb, mongoose, redis, ioredis |
| Messaging | amqplib (RabbitMQ), kafkajs, aws-sdk (SQS, SNS, DynamoDB) |
| GraphQL | graphql, apollo-server, apollo-client |
| RPC | grpc-js, connect |
Each instrumentation produces a span per call — request method + route for HTTP, query text for SQL, command for Redis, etc.
Verifying It's Working
- Start your service with the
--requireflag (orNODE_OPTIONS) and the OTel env vars set - Hit an instrumented endpoint
- In CodeXray, open Applications → find your service → Traces tab
- Traces should appear within a minute, named by HTTP method + route
If nothing arrives, enable debug logging:
export OTEL_LOG_LEVEL="debug"
The SDK then prints every exported span batch and any HTTP error from the collector to stdout.
Custom Spans for Business Logic
Auto-instrumentation covers framework and library calls — for your own functions, add spans manually:
import { trace } from '@opentelemetry/api';
const tracer = trace.getTracer('my-service');
async function processOrder(orderId) {
return tracer.startActiveSpan('processOrder', async (span) => {
span.setAttribute('order.id', orderId);
try {
// your business logic ...
} finally {
span.end();
}
});
}
The new span automatically becomes a child of whatever HTTP request span is currently active.
Disabling a Specific Instrumentation
If you don't want a particular library traced (e.g. redis is too chatty), disable it via env:
export OTEL_NODE_DISABLED_INSTRUMENTATIONS="redis,ioredis"
The bundle still loads but skips those instrumentation modules.
Next Steps
- OpenTelemetry for Next.js — Next.js needs a different path (no
--requirebecause of standalone build) - Traces Overview — the full Traces tab walkthrough
- OpenTelemetry for PHP · for Go · for Java · for Python — instrument your other services
- eBPF-based Tracing — immediate coverage for services you can't modify