ECMAScript module support
editECMAScript module support
editECMAScript module support is currently incomplete and experimental. It was added in version v3.48.0.
The Elastic APM Node.js agent includes limited and experimental support for auto-instrumentation of ECMAScript modules (ESM) — i.e. modules loaded via the import ...
statement or the import(...)
expression. Support is based on the experimental Node.js Loaders API, which requires passing the --experimental-loader
option to node.
As a first example, the APM agent can provide HTTP tracing for the following Express server:
// server.mjs import bodyParser from 'body-parser' import express from 'express' const app = express() app.use(bodyParser.json()) app.get('/hello/:name', function (request, reply) { reply.send({ hello: request.params.name }) }) app.listen({ port: 3000}, () => { console.log('Server is listening. Try:\n curl -i http://localhost:3000/hello/grace') })
when invoked as follows:
export ELASTIC_APM_SERVER_URL='https://...apm...cloud.es.io:443' export ELASTIC_APM_SECRET_TOKEN='...' node -r elastic-apm-node/start.js \ --experimental-loader=elastic-apm-node/loader.mjs' \ node server.mjs
The current ESM support is limited — only a subset of the modules listed at Supported technologies are implemented. More will be added in subsequent releases. See below for full details.
The ESM limitations only affects the agent’s automatic instrumentation. Other functionality — such as metrics collection, manual instrumentation and error capture — still work when using ES modules.
Enabling ESM auto-instrumentation
editEnabling ESM auto-instrumentation requires starting Node.js with the --experimental-loader=elastic-apm-node/loader.mjs
option. This can be done by passing the argument on the command line or by setting the NODE_OPTIONS
environment variable.
node --experimental-loader=elastic-apm-node/loader.mjs server.mjs # or NODE_OPTIONS='--experimental-loader=elastic-apm-node/loader.mjs' node server.mjs
As well, the APM agent must also be separately started — for example via --require=elastic-apm-node/start.js
. See Starting the agent for the various ways of starting the APM agent.
Supported Node.js versions
editAutomatic instrumentation of ES modules is based on the experimental Node.js Loaders API. ESM support in the Elastic APM Node.js agent will remain experimental while the Loaders API is experimental.
ESM auto-instrumentation is only supported for Node.js versions that match ^12.20.0 || ^14.13.1 || ^16.0.0 || ^18.1.0 <20
.
The behavior when using node --experimental-loader=elastic-apm-node/loader.mjs
with earlier Node.js versions is undefined and unsupported.
Notably, ESM auto-instrumentation is not supported with Node.js v20 because of changes in the Loaders API. Using the loader with Node.js v20 can result in crashes in import ...
statements that attempt named imports from some CommonJS modules. The error message will be of the form SyntaxError: The requested module '<module name>' does not provide an export named '<export name>'
. (You can track this issue for progress.)
Supported modules
editAutomatic instrumentation of ES modules is currently limited as described here. Note that the supported module version ranges often differ from those for CommonJS (i.e. require()
) auto-instrumentation.
Module | Version | Note | |
---|---|---|---|
|
>=3.15.0 <4 |
||
|
^4.0.0 |
||
|
>=3.5.0 |
||
|
See Supported Node.js versions above. |
||
|
See Supported Node.js versions above. |
||
|
>=2 <6 |
||
|
>=0.20.0 <3 |
Also, only with pg@8. |
|
|
^8 |
Troubleshooting ESM support
editIf you see an error like the following, then you are attempting to use ESM auto-instrumentation support with too early of a version of Node.js. See Supported Node.js versions above.
file:///.../node_modules/import-in-the-middle/hook.mjs:6 import { createHook } from './hook.js' ^^^^^^^^^^ SyntaxError: The requested module './hook.js' is expected to be of type CommonJS, which does not support named exports. CommonJS modules can be imported by importing the default export. For example: import pkg from './hook.js'; const { createHook } = pkg; at ModuleJob._instantiate (internal/modules/esm/module_job.js:98:21) at async ModuleJob.run (internal/modules/esm/module_job.js:137:5) at async Loader.import (internal/modules/esm/loader.js:165:24) at async internal/process/esm_loader.js:57:9 at async Object.loadESM (internal/process/esm_loader.js:67:5)