Instrumenting a Node.js service with the Elastic Distribution of OpenTelemetry for Node.js adds Elastic-supported OpenTelemetry telemetry without loading the legacy Elastic APM agent in the same process. It fits Express, HTTP, and other supported Node.js services that need automatic spans and metrics in Elastic Observability.
The EDOT package, @elastic/opentelemetry-node, starts during the Node.js preload phase through the --import option. Starting it before application modules load allows the SDK to patch supported libraries such as http and express before the service handles traffic.
EDOT Node.js reads standard OTEL_* environment variables and sends telemetry by OTLP to either an Elastic Cloud Managed OTLP endpoint or an EDOT Collector that exports to Elastic. Keep the Elastic write key in the deployment secret, service manager, or Collector configuration, and use one instrumentation agent per process to avoid duplicate spans.
$ node --version v22.22.3
EDOT Node.js supports Node.js 18.19.0, 20.6.0, or later. Check the runtime used by the service manager or container image, not only the local developer shell.
$ npm install @elastic/opentelemetry-node added 273 packages in 12s
Old start option: --require elastic-apm-node/start New start option: --import @elastic/opentelemetry-node
Do not run EDOT Node.js beside another APM agent in the same Node.js process. Multiple agents can patch the same modules and produce duplicate or conflicting telemetry.
export OTEL_EXPORTER_OTLP_ENDPOINT="https://otlp.elastic.example.net" export OTEL_EXPORTER_OTLP_HEADERS="Authorization=ApiKey REDACTED_API_KEY" export OTEL_SERVICE_NAME="checkout-api"
Use the Managed OTLP endpoint for Elastic Cloud, or use the local EDOT Collector endpoint when a Collector owns the Elastic credentials. Self-managed, ECE, and ECK deployments need an OTLP-compatible Collector or gateway path instead of the Elastic Cloud Managed OTLP endpoint.
$ node --import @elastic/opentelemetry-node server.cjs
{"name":"elastic-otel-node","msg":"start EDOT Node.js"}
checkout-api listening on http://127.0.0.1:3000
Use NODE_OPTIONS=“--import @elastic/opentelemetry-node” when a process manager owns the final node command and only accepts environment variables.
$ curl --silent http://127.0.0.1:3000/checkout
{"status":"paid","id":"order-1001"}
The first request gives EDOT a trace to export. Use a route that passes through the framework, middleware, and downstream calls that should appear in Elastic Observability.
Kibana -> Observability -> Applications -> Service Inventory Service: checkout-api Transaction: GET /checkout
The service can take a minute or two to appear after startup and traffic. If it does not appear, check the service name, OTLP endpoint, Authorization header, and Collector or endpoint logs.