Notable Changes
require(esm) is now enabled by default
Support for loading native ES modules using require() had been available on v20.x under the command line flag --experimental-require-module, and available by default on v22.x and v23.x. In this release, it is now no longer behind a flag on v20.x.
This feature has been tested on v23.x and v22.x, and we are looking for user feedback from v20.x to make more final tweaks before fully stabilizing it. When the Node.js instance encounters a native ES module in require() somewhere outside node_modules
for the first time, it will emit an experimental warning unless require()
comes from a path that contains node_modules
. If there happens to be any regressions caused by this feature, users can report it to the Node.js issue tracker. Meanwhile this feature can also be disabled using --no-experimental-require-module
as a workaround.
With this feature enabled, Node.js will no longer throw ERR_REQUIRE_ESM
if require()
is used to load a ES module. It can, however, throw ERR_REQUIRE_ASYNC_MODULE
if the ES module being loaded or its dependencies contain top-level await
. When the ES module is loaded successfully by require()
, the returned object will either be a ES module namespace object similar to what's returned by import()
, or what gets exported as "module.exports"
in the ES module.
Users can check process.features.require_module
to see whether require(esm)
is enabled in the current Node.js instance. For packages, the "module-sync"
exports condition can be used as a way to detect require(esm)
support in the current Node.js instance and allow both require()
and import
to load the same native ES module. See the documentation for more details about this feature.
Contributed by Joyee Cheung in #55085
Module syntax detection is now enabled by default
Module syntax detection (the --experimental-detect-module
flag) is now
enabled by default. Use --no-experimental-detect-module
to disable it if
needed.
Syntax detection attempts to run ambiguous files as CommonJS, and if the module
fails to parse as CommonJS due to ES module syntax, Node.js tries again and runs
the file as an ES module.
Ambiguous files are those with a .js
or no extension, where the nearest parent
package.json
has no "type"
field (either "type": "module"
or
"type": "commonjs"
).
Syntax detection should have no performance impact on CommonJS modules, but it
incurs a slight performance penalty for ES modules; add "type": "module"
to
the nearest parent package.json
file to eliminate the performance cost.
A use case unlocked by this feature is the ability to use ES module syntax in
extensionless scripts with no nearby package.json
.
Thanks to Geoffrey Booth for making this work on #53619.
Other Notable Changes
- [
285bb4ee14
] - crypto: update root certificates to NSS 3.107 (Node.js GitHub Bot) #56566 - [
73b5c16684
] - (SEMVER-MINOR) worker: add postMessageToThread (Paolo Insogna) #53682 - [
de313b2336
] - (SEMVER-MINOR) module: only emit require(esm) warning under --trace-require-module (Joyee Cheung) #56194 - [
4fba01911d
] - (SEMVER-MINOR) process: add process.features.require_module (Joyee Cheung) #55241 - [
df8a045afe
] - (SEMVER-MINOR) module: implement the "module-sync" exports condition (Joyee Cheung) #54648 - [
f9dc1eaef5
] - (SEMVER-MINOR) module: add __esModule to require()'d ESM (Joyee Cheung) #52166
Commits
- [
d84be843e3
] - benchmark: add validateStream to styleText bench (Rafael Gonzaga) #56556 - [
d8eaf5b9b8
] - build: fix compatibility with V8'sdepot_tools
(Richard Lau) #57330 - [
1ee4bf9690
] - build: test macos-13 on GitHub actions (Michaël Zasso) #56307 - [
1cc8d69882
] - build: build v8 with -fvisibility=hidden on macOS (Joyee Cheung) #56275 - [
52f1f7e22b
] - child_process: fix parsing messages with splitted length field (Maksim Gorkov) #56106 - [
5ef3c3c996
] - crypto: add missing return value check (Michael Dawson) #56615 - [
285bb4ee14
] - crypto: update root certificates to NSS 3.107 (Node.js GitHub Bot) #56566 - [
46ceb9dc1c
] - deps: update timezone to 2025a (Node.js GitHub Bot) #56876 - [
d4ca38fe8e
] - deps: macro ENODATA is deprecated in libc++ (Cheng) #56698 - [
15214e6508
] - deps: update simdutf to 6.0.3 (Node.js GitHub Bot) #56567 - [
1e44f5d84b
] - deps: update simdutf to 5.7.2 (Node.js GitHub Bot) #56388 - [
b92ff7be38
] - deps: update googletest to 7d76a23 (Node.js GitHub Bot) #56387 - [
e1b71a81a9
] - deps: update googletest to e54519b (Node.js GitHub Bot) #56370 - [
c0d45e7f38
] - deps: update simdutf to 5.7.0 (Node.js GitHub Bot) #56332 - [
d69107f5a8
] - deps: update icu to 76.1 (Node.js GitHub Bot) #55551 - [
5c9a397699
] - deps: V8: backport 9ab40592f697 (Lu Yahan) #56781 - [
8342233f6d
] - deps: update corepack to 0.31.0 (Node.js GitHub Bot) #56795 - [
561493d35e
] - deps,src: simplify base64 encoding (Daniel Lemire) #52714 - [
6207b2936c
] - doc: move anatoli to emeritus (Michael Dawson) #56592 - [
b0ab483400
] - doc: fix styles of the expandable TOC (Antoine du Hamel) #56755 - [
53e4dc2a82
] - doc: add "Skip to content" button (Antoine du Hamel) #56750 - [
33ee4645c3
] - doc: improve accessibility of expandable lists (Antoine du Hamel) #56749 - [
b514438418
] - doc: add note regarding commit message trailers (Dario Piotrowicz) #56736 - [
627f2997e3
] - doc: fix typo in example code for util.styleText (Robin Mehner) #56720 - [
68548dcb48
] - doc: fix inconsistencies inWeakSet
andWeakMap
comparison details (Shreyans Pathak) #56683 - [
337cfb2549
] - doc: add RafaelGSS as latest sec release stewards (Rafael Gonzaga) #56682 - [
e890c86d7b
] - doc: clarify cjs/esm diff inqueueMicrotask()
vsprocess.nextTick()
(Dario Piotrowicz) #56659 - [
978263923f
] - doc:WeakSet
andWeakMap
comparison details (Shreyans Pathak) #56648 - [
aba280ccd8
] - doc: mention prepare --security (Rafael Gonzaga) #56617 - [
0a009a527b
] - doc: tweak info on reposts in ambassador program (Michael Dawson) #56589 - [
d2f09e2ab3
] - doc: add type stripping to ambassadors program (Marco Ippolito) #56598 - [
b0b77d7fbe
] - doc: improve internal documentation on built-in snapshot (Joyee Cheung) #56505 - [
4b3e7fee94
] - doc: document CLI way to open the nodejs/bluesky PR (Antoine du Hamel) #56506 - [
03878b0384
] - doc: update gcc-version for ubuntu-lts (Kunal Kumar) #56553 - [
acbbd7c1a6
] - doc: fix parentheses in options (Tobias Nießen) #56563 - [
3fe80c30b8
] - doc: include CVE to EOL lines as sec release process (Rafael Gonzaga) #56520 - [
ff8af58046
] - doc: add esm examples to node:trace_events (Alfredo González) #56514 - [
27b9cfd135
] - doc: add message for Ambassadors to promote (Michael Dawson) #56235 - [
020c939da1
] - doc: allow request for TSC reviews via the GitHub UI (Antoine du Hamel) #56493 - [
1ef9c9a354
] - doc: add example for piping ReadableStream (Gabriel Schulhof) #56415 - [
e675c3a7fc
] - doc: expand description ofparseArg
'sdefault
(Kevin Gibbons) #54431 - [
bc756da876
] - doc: use<ul>
instead of<ol>
inSECURITY.md
(Antoine du Hamel) #56346 - [
ad59c82a49
] - doc: clarify that WASM is trusted (Matteo Collina) #56345 - [
8e76cc69e5
] - doc: move dual package shipping docs to separate repo (Joyee Cheung) #55444 - [
9fda8e29cd
] - doc: mark--env-file-if-exists
flag as experimental (Juan José) #56893 - [
9e975f1a7d
] - doc: fix link and history ofSourceMap
sections (Antoine du Hamel) #57098 - [
64ce95b8fc
] - doc: updaterequire(ESM)
history and stability status (Antoine du Hamel) #55199 - [
697a39248b
] - doc: fix history ofprocess.features
(Antoine du Hamel) #54897 - [
7c38e503a3
] - doc: add documentation for process.features (Marco Ippolito) #54897 - [
c85b386a39
] - esm: fix jsdoc type refs toModuleJobBase
in esm/loader (Jacob Smith) #56499 - [
4813a6a66c
] - esm: throwERR_REQUIRE_ESM
instead ofERR_INTERNAL_ASSERTION
(Antoine du Hamel) #54868 - [
0d327c8e47
] - esm: refactorget_format
(Antoine du Hamel) #53872 - [
e87db6c9bc
] - events: add hasEventListener util for validate (Sunghoon) #55230 - [
674b932f33
] - http: don't emit error after destroy (Robert Nagy) #55457 - [
4c24ef8f71
] - http2: omit server name when HTTP2 host is IP address (islandryu) #56530 - [
533afe8124
] - lib: reduce amount of caught URL errors (Yagiz Nizipli) #52658 - [
34221a1d6e
] - lib: allow CJS source map cache to be reclaimed (Chengzhong Wu) #51711 - [
f13589f1f9
] - lib,src: iterate module requests of a module wrap in JS (Chengzhong Wu) #52058 - [
6afee9ea43
] - meta: move one or more collaborators to emeritus (Node.js GitHub Bot) #56580 - [
85bb738739
] - meta: add codeowners of security release document (Rafael Gonzaga) #56521 - [
48f9ca0992
] - meta: move one or more collaborators to emeritus (Node.js GitHub Bot) #56342 - [
4d724121b4
] - meta: move MoLow to TSC regular member (Moshe Atlow) #56276 - [
5e2dab7868
] - module: fix badrequire.resolve
with option paths for.
and..
(Dario Piotrowicz) #56735 - [
f507c05060
] - module: simplify --inspect-brk handling (Joyee Cheung) #55679 - [
ed2d373e5a
] - module: disable require(esm) for policy and network import (Joyee Cheung) #56927 - [
de313b2336
] - (SEMVER-MINOR) module: only emit require(esm) warning under --trace-require-module (Joyee Cheung) #56194 - [
3d89e6b6fa
] - module: mark evaluation rejection in require(esm) as handled (Joyee Cheung) #56122 - [
e01dd4bd4f
] - module: do not warn when require(esm) comes from node_modules (Joyee Cheung) #55960 - [
011e6e0032
] - module: fix error thrown from require(esm) hitting TLA repeatedly (Joyee Cheung) #55520 - [
fdf50289c6
] - module: trim off internal stack frames for require(esm) warnings (Joyee Cheung) #55496 - [
8d33f78ca5
] - module: allow ESM that failed to be required to be re-imported (Joyee Cheung) #55502 - [
8192dd6cf3
] - module: include module information in require(esm) warning (Joyee Cheung) #55397 - [
1db210a0ec
] - module: check --experimental-require-module separately from detection (Joyee Cheung) #55250 - [
cf8701c866
] - module: use kNodeModulesRE to detect node_modules (Joyee Cheung) #55243 - [
dc66632261
] - module: support 'module.exports' interop export in require(esm) (Guy Bedford) #54563 - [
1ac1dda9a4
] - (SEMVER-MINOR) module: unflag --experimental-require-module (Joyee Cheung) #55085 - [
683c93f45f
] - module: refator ESM loader for adding future synchronous hooks (Joyee Cheung) #54769 - [
df8a045afe
] - (SEMVER-MINOR) module: implement the "module-sync" exports condition (Joyee Cheung) #54648 - [
249d82b686
] - module: report unfinished TLA in ambiguous modules (Antoine du Hamel) #54980 - [
1925d729f9
] - module: remove bogus assertion in CJS entrypoint handling with --import (Joyee Cheung) #54592 - [
d1331fccb2
] - module: do not warn for typeless package.json when there isn't one (Joyee Cheung) #54045 - [
9916458b44
] - (SEMVER-MINOR) module: unflag detect-module (Geoffrey Booth) #53619 - [
f9dc1eaef5
] - (SEMVER-MINOR) module: add __esModule to require()'d ESM (Joyee Cheung) #52166 - [
b86f575504
] - module: do not set CJS variables for Worker eval (Antoine du Hamel) #53050 - [
30ed93db12
] - module: cache synchronous module jobs before linking (Joyee Cheung) #52868 - [
a03faf289d
] - module: support ESM detection in the CJS loader (Joyee Cheung) #52047 - [
b07ad39bda
] - module: detect ESM syntax by trying to recompile as SourceTextModule (Joyee Cheung) #52413 - [
132a5c190f
] - module: eliminate performance cost of detection for cjs entry (Geoffrey Booth) #52093 - [
55a57a189f
] - node-api: remove deprecated attribute from napi_module_register (Vladimir Morozov) #56162 - [
4fba01911d
] - (SEMVER-MINOR) process: add process.features.require_module (Joyee Cheung) #55241 - [
c0fad18ac0
] - src: add nullptr handling from X509_STORE_new() (Burkov Egor) #56700 - [
5b88d48cbb
] - src: add default value for RSACipherConfig mode field (Burkov Egor) #56701 - [
e3b69e57a6
] - src: fix build with GCC 15 (tjuhaszrh) #56740 - [
a7c1d8c0e8
] - src: initialize FSReqWrapSync in path that uses it (Michaël Zasso) #56613 - [
c06ac66356
] - src: fix undefined script name in error source (Chengzhong Wu) #56502 - [
500f3ccc66
] - src: lock the thread properly in snapshot builder (Joyee Cheung) #56327 - [
cf25a5edeb
] - src: drain platform tasks before creating startup snapshot (Chengzhong Wu) #56403 - [
8af1b53bb8
] - src: safely remove the last line from dotenv (Shima Ryuhei) #55982 - [
bb57e909aa
] - src: removebase64
fromprocess.versions
(Richard Lau) #53442 - [
b8c89a693e
] - src: add--env-file-if-exists
flag (Bosco Domingo) #53060 - [
9097de073a
] - src: don't match after--
inDotenv::GetPathFromArgs
(Aviv Keller) #54237 - [
ececd225b6
] - src: implement IsInsideNodeModules() in C++ (Joyee Cheung) #55286 - [
18593b7d3e
] - src: refactor embedded entrypoint loading (Joyee Cheung) #53573 - [
d7aefc0524
] - stream: fix typo in ReadableStreamBYOBReader.readIntoRequests (Mattias Buelens) #56560 - [
fe5f7bcd47
] - stream: validate undefined sizeAlgorithm in WritableStream (Jason Zhang) #56067 - [
12744c1fd4
] - test: reduce number of written chunks (Luigi Pinca) #56757 - [
e121d7d62c
] - test: fix invalid common.mustSucceed() usage (Luigi Pinca) #56756 - [
11b82de7ed
] - test: use strict mode in global setters test (Rich Trott) #56742 - [
f9d6e35c5e
] - test: cleanup and simplify test-crypto-aes-wrap (James M Snell) #56748 - [
792ce98699
] - test: do not use common.isMainThread (Luigi Pinca) #56768 - [
4f0cf475e0
] - test: add test that uses multibyte for path and resolves modules (yamachu) #56696 - [
3bc8d273c2
] - test: add missing test for env file (Jonas) #56642 - [
ad39367712
] - test: enforce strict mode in test-zlib-const (Rich Trott) #56689 - [
ca79914137
] - test: test-stream-compose.js doesn't need internals (Meghan Denny) #56619 - [
08bde67101
] - test: add maxCount and gcOptions to gcUntil() (Joyee Cheung) #56522 - [
40a0f6f6e3
] - test: mark test-worker-prof as flaky on smartos (Joyee Cheung) #56583 - [
d17bf2f62a
] - test: update test-child-process-bad-stdio to use node:test (Colin Ihrig) #56562 - [
5660b99b43
] - test: disable openssl 3.4.0 incompatible tests (Jelle van der Waa) #56160 - [
861c99f351
] - test: make test-crypto-hash compatible with OpenSSL > 3.4.0 (Jelle van der Waa) #56160 - [
597a39b5f9
] - test: update error code in tls-psk-circuit for for OpenSSL 3.4 (sebastianas) #56420 - [
721e9e1217
] - test: add initial test426 coverage (Chengzhong Wu) #56436 - [
cfe5380c44
] - test: update test-set-http-max-http-headers to use node:test (Colin Ihrig) #56439 - [
51ff71a87a
] - test: update test-child-process-windows-hide to use node:test (Colin Ihrig) #56437 - [
d6aca0cd89
] - test: increase spin for eventloop test on s390 (Michael Dawson) #56228 - [
82461af6ec
] - test: migrate message eval tests from Python to JS (Yiyun Lei) #50482 - [
5083bbb2bb
] - test: remove async-hooks/test-writewrap flaky designation (Luigi Pinca) #56048 - [
b4b26e973d
] - test: deflake test-esm-loader-hooks-inspect-brk (Luigi Pinca) #56050 - [
182be26b8a
] - test: update WPT for url to 67880a4eb83ca9aa732eec4b35a1971ff5bf37ff (Node.js GitHub Bot) #55999 - [
e67a84902f
] - test_runner: remove unused errors (Pietro Marchini) #56607 - [
4274c6a015
] - test_runner: run single test file benchmark (Pietro Marchini) #56479 - [
e57004458b
] - tools: update doc to new version (Node.js GitHub Bot) #56259 - [
e039f2b571
] - tools: do not throw on missingcreate-release-proposal.sh
(Antoine du Hamel) #56704 - [
9a1e314498
] - tools: fix tools-deps-update (Daniel Lemire) #56684 - [
d6469b5287
] - tools: do not throw on missingcreate-release-proposal.sh
(Antoine du Hamel) #56695 - [
e162476fdc
] - tools: fix permissions inlint-release-proposal
workflow (Antoine du Hamel) #56614 - [
914b4675c8
] - tools: editcreate-release-proposal
workflow (Antoine du Hamel) #56540 - [
4ff9aa7235
] - tools: validate commit list as part oflint-release-commit
(Antoine du Hamel) #56291 - [
589d0ae8ea
] - tools: fix loong64 build failed (Xiao-Tao) #56466 - [
bc8c39bff8
] - tools: disable unneeded rule ignoring in Python linting (Rich Trott) #56429 - [
3b130002bb
] - tools: add release line label when opening release proposal (Antoine du Hamel) #56317 - [
73b5c16684
] - (SEMVER-MINOR) worker: add postMessageToThread (Paolo Insogna) #53682