• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Modules: ECMAScript modules
2
3<!--introduced_in=v8.5.0-->
4
5<!-- type=misc -->
6
7<!-- YAML
8added: v8.5.0
9changes:
10  - version: v18.20.0
11    pr-url: https://github.com/nodejs/node/pull/50140
12    description: Add experimental support for import attributes.
13  - version: v18.19.0
14    pr-url: https://github.com/nodejs/node/pull/44710
15    description: Module customization hooks are executed off the main thread.
16  - version:
17    - v18.6.0
18    pr-url: https://github.com/nodejs/node/pull/42623
19    description: Add support for chaining module customization hooks.
20  - version:
21    - v17.1.0
22    - v16.14.0
23    pr-url: https://github.com/nodejs/node/pull/40250
24    description: Add experimental support for import assertions.
25  - version:
26    - v17.0.0
27    - v16.12.0
28    pr-url: https://github.com/nodejs/node/pull/37468
29    description:
30      Consolidate customization hooks, removed `getFormat`, `getSource`,
31      `transformSource`, and `getGlobalPreloadCode` hooks
32      added `load` and `globalPreload` hooks
33      allowed returning `format` from either `resolve` or `load` hooks.
34  - version:
35    - v15.3.0
36    - v14.17.0
37    - v12.22.0
38    pr-url: https://github.com/nodejs/node/pull/35781
39    description: Stabilize modules implementation.
40  - version:
41    - v14.13.0
42    - v12.20.0
43    pr-url: https://github.com/nodejs/node/pull/35249
44    description: Support for detection of CommonJS named exports.
45  - version: v14.8.0
46    pr-url: https://github.com/nodejs/node/pull/34558
47    description: Unflag Top-Level Await.
48  - version:
49    - v14.0.0
50    - v13.14.0
51    - v12.20.0
52    pr-url: https://github.com/nodejs/node/pull/31974
53    description: Remove experimental modules warning.
54  - version:
55    - v13.2.0
56    - v12.17.0
57    pr-url: https://github.com/nodejs/node/pull/29866
58    description: Loading ECMAScript modules no longer requires a command-line flag.
59  - version: v12.0.0
60    pr-url: https://github.com/nodejs/node/pull/26745
61    description:
62      Add support for ES modules using `.js` file extension via `package.json`
63      `"type"` field.
64-->
65
66> Stability: 2 - Stable
67
68## Introduction
69
70<!--name=esm-->
71
72ECMAScript modules are [the official standard format][] to package JavaScript
73code for reuse. Modules are defined using a variety of [`import`][] and
74[`export`][] statements.
75
76The following example of an ES module exports a function:
77
78```js
79// addTwo.mjs
80function addTwo(num) {
81  return num + 2;
82}
83
84export { addTwo };
85```
86
87The following example of an ES module imports the function from `addTwo.mjs`:
88
89```js
90// app.mjs
91import { addTwo } from './addTwo.mjs';
92
93// Prints: 6
94console.log(addTwo(4));
95```
96
97Node.js fully supports ECMAScript modules as they are currently specified and
98provides interoperability between them and its original module format,
99[CommonJS][].
100
101<!-- Anchors to make sure old links find a target -->
102
103<i id="esm_package_json_type_field"></i><i id="esm_package_scope_and_file_extensions"></i><i id="esm_input_type_flag"></i>
104
105## Enabling
106
107<!-- type=misc -->
108
109Node.js has two module systems: [CommonJS][] modules and ECMAScript modules.
110
111Authors can tell Node.js to use the ECMAScript modules loader via the `.mjs`
112file extension, the `package.json` [`"type"`][] field, the [`--input-type`][]
113flag, or the [`--experimental-default-type`][] flag. Outside of those cases,
114Node.js will use the CommonJS module loader. See [Determining module system][]
115for more details.
116
117<!-- Anchors to make sure old links find a target -->
118
119<i id="esm_package_entry_points"></i><i id="esm_main_entry_point_export"></i><i id="esm_subpath_exports"></i><i id="esm_package_exports_fallbacks"></i><i id="esm_exports_sugar"></i><i id="esm_conditional_exports"></i><i id="esm_nested_conditions"></i><i id="esm_self_referencing_a_package_using_its_name"></i><i id="esm_internal_package_imports"></i><i id="esm_dual_commonjs_es_module_packages"></i><i id="esm_dual_package_hazard"></i><i id="esm_writing_dual_packages_while_avoiding_or_minimizing_hazards"></i><i id="esm_approach_1_use_an_es_module_wrapper"></i><i id="esm_approach_2_isolate_state"></i>
120
121## Packages
122
123This section was moved to [Modules: Packages](packages.md).
124
125## `import` Specifiers
126
127### Terminology
128
129The _specifier_ of an `import` statement is the string after the `from` keyword,
130e.g. `'node:path'` in `import { sep } from 'node:path'`. Specifiers are also
131used in `export from` statements, and as the argument to an `import()`
132expression.
133
134There are three types of specifiers:
135
136* _Relative specifiers_ like `'./startup.js'` or `'../config.mjs'`. They refer
137  to a path relative to the location of the importing file. _The file extension
138  is always necessary for these._
139
140* _Bare specifiers_ like `'some-package'` or `'some-package/shuffle'`. They can
141  refer to the main entry point of a package by the package name, or a
142  specific feature module within a package prefixed by the package name as per
143  the examples respectively. _Including the file extension is only necessary
144  for packages without an [`"exports"`][] field._
145
146* _Absolute specifiers_ like `'file:///opt/nodejs/config.js'`. They refer
147  directly and explicitly to a full path.
148
149Bare specifier resolutions are handled by the [Node.js module
150resolution and loading algorithm][].
151All other specifier resolutions are always only resolved with
152the standard relative [URL][] resolution semantics.
153
154Like in CommonJS, module files within packages can be accessed by appending a
155path to the package name unless the package's [`package.json`][] contains an
156[`"exports"`][] field, in which case files within packages can only be accessed
157via the paths defined in [`"exports"`][].
158
159For details on these package resolution rules that apply to bare specifiers in
160the Node.js module resolution, see the [packages documentation](packages.md).
161
162### Mandatory file extensions
163
164A file extension must be provided when using the `import` keyword to resolve
165relative or absolute specifiers. Directory indexes (e.g. `'./startup/index.js'`)
166must also be fully specified.
167
168This behavior matches how `import` behaves in browser environments, assuming a
169typically configured server.
170
171### URLs
172
173ES modules are resolved and cached as URLs. This means that special characters
174must be [percent-encoded][], such as `#` with `%23` and `?` with `%3F`.
175
176`file:`, `node:`, and `data:` URL schemes are supported. A specifier like
177`'https://example.com/app.js'` is not supported natively in Node.js unless using
178a [custom HTTPS loader][].
179
180#### `file:` URLs
181
182Modules are loaded multiple times if the `import` specifier used to resolve
183them has a different query or fragment.
184
185```js
186import './foo.mjs?query=1'; // loads ./foo.mjs with query of "?query=1"
187import './foo.mjs?query=2'; // loads ./foo.mjs with query of "?query=2"
188```
189
190The volume root may be referenced via `/`, `//`, or `file:///`. Given the
191differences between [URL][] and path resolution (such as percent encoding
192details), it is recommended to use [url.pathToFileURL][] when importing a path.
193
194#### `data:` imports
195
196<!-- YAML
197added: v12.10.0
198-->
199
200[`data:` URLs][] are supported for importing with the following MIME types:
201
202* `text/javascript` for ES modules
203* `application/json` for JSON
204* `application/wasm` for Wasm
205
206```js
207import 'data:text/javascript,console.log("hello!");';
208import _ from 'data:application/json,"world!"' with { type: 'json' };
209```
210
211`data:` URLs only resolve [bare specifiers][Terminology] for builtin modules
212and [absolute specifiers][Terminology]. Resolving
213[relative specifiers][Terminology] does not work because `data:` is not a
214[special scheme][]. For example, attempting to load `./foo`
215from `data:text/javascript,import "./foo";` fails to resolve because there
216is no concept of relative resolution for `data:` URLs.
217
218#### `node:` imports
219
220<!-- YAML
221added:
222  - v14.13.1
223  - v12.20.0
224changes:
225  - version:
226      - v16.0.0
227      - v14.18.0
228    pr-url: https://github.com/nodejs/node/pull/37246
229    description: Added `node:` import support to `require(...)`.
230-->
231
232`node:` URLs are supported as an alternative means to load Node.js builtin
233modules. This URL scheme allows for builtin modules to be referenced by valid
234absolute URL strings.
235
236```js
237import fs from 'node:fs/promises';
238```
239
240<a id="import-assertions"></a>
241
242## Import attributes
243
244<!-- YAML
245added:
246  - v17.1.0
247  - v16.14.0
248changes:
249  - version: v18.20.0
250    pr-url: https://github.com/nodejs/node/pull/50140
251    description: Switch from Import Assertions to Import Attributes.
252-->
253
254> Stability: 1.1 - Active development
255
256> This feature was previously named "Import assertions", and using the `assert`
257> keyword instead of `with`. Any uses in code of the prior `assert` keyword
258> should be updated to use `with` instead.
259
260The [Import Attributes proposal][] adds an inline syntax for module import
261statements to pass on more information alongside the module specifier.
262
263```js
264import fooData from './foo.json' with { type: 'json' };
265
266const { default: barData } =
267  await import('./bar.json', { with: { type: 'json' } });
268```
269
270Node.js supports the following `type` values, for which the attribute is
271mandatory:
272
273| Attribute `type` | Needed for       |
274| ---------------- | ---------------- |
275| `'json'`         | [JSON modules][] |
276
277## Builtin modules
278
279[Core modules][] provide named exports of their public API. A
280default export is also provided which is the value of the CommonJS exports.
281The default export can be used for, among other things, modifying the named
282exports. Named exports of builtin modules are updated only by calling
283[`module.syncBuiltinESMExports()`][].
284
285```js
286import EventEmitter from 'node:events';
287const e = new EventEmitter();
288```
289
290```js
291import { readFile } from 'node:fs';
292readFile('./foo.txt', (err, source) => {
293  if (err) {
294    console.error(err);
295  } else {
296    console.log(source);
297  }
298});
299```
300
301```js
302import fs, { readFileSync } from 'node:fs';
303import { syncBuiltinESMExports } from 'node:module';
304import { Buffer } from 'node:buffer';
305
306fs.readFileSync = () => Buffer.from('Hello, ESM');
307syncBuiltinESMExports();
308
309fs.readFileSync === readFileSync;
310```
311
312## `import()` expressions
313
314[Dynamic `import()`][] is supported in both CommonJS and ES modules. In CommonJS
315modules it can be used to load ES modules.
316
317## `import.meta`
318
319* {Object}
320
321The `import.meta` meta property is an `Object` that contains the following
322properties.
323
324### `import.meta.url`
325
326* {string} The absolute `file:` URL of the module.
327
328This is defined exactly the same as it is in browsers providing the URL of the
329current module file.
330
331This enables useful patterns such as relative file loading:
332
333```js
334import { readFileSync } from 'node:fs';
335const buffer = readFileSync(new URL('./data.proto', import.meta.url));
336```
337
338### `import.meta.resolve(specifier)`
339
340<!-- YAML
341added:
342  - v13.9.0
343  - v12.16.2
344changes:
345  - version: v18.19.0
346    pr-url: https://github.com/nodejs/node/pull/49028
347    description: Unflag `import.meta.resolve``, with `parentURL` parameter still
348                 flagged.
349  - version: v18.19.0
350    pr-url: https://github.com/nodejs/node/pull/49038
351    description: This API no longer throws when targeting `file:` URLs that do
352                 not map to an existing file on the local FS.
353  - version: v18.19.0
354    pr-url: https://github.com/nodejs/node/pull/44710
355    description: This API now returns a string synchronously instead of a Promise.
356  - version:
357      - v16.2.0
358      - v14.18.0
359    pr-url: https://github.com/nodejs/node/pull/38587
360    description: Add support for WHATWG `URL` object to `parentURL` parameter.
361-->
362
363> Stability: 1.2 - Release candidate
364
365* `specifier` {string} The module specifier to resolve relative to the
366  current module.
367* Returns: {string} The absolute URL string that the specifier would resolve to.
368
369[`import.meta.resolve`][] is a module-relative resolution function scoped to
370each module, returning the URL string.
371
372```js
373const dependencyAsset = import.meta.resolve('component-lib/asset.css');
374// file:///app/node_modules/component-lib/asset.css
375import.meta.resolve('./dep.js');
376// file:///app/dep.js
377```
378
379All features of the Node.js module resolution are supported. Dependency
380resolutions are subject to the permitted exports resolutions within the package.
381
382**Caveats**:
383
384* This can result in synchronous file-system operations, which
385  can impact performance similarly to `require.resolve`.
386* This feature is not available within custom loaders (it would
387  create a deadlock).
388
389**Non-standard API**:
390
391When using the `--experimental-import-meta-resolve` flag, that function accepts
392a second argument:
393
394* `parent` {string|URL} An optional absolute parent module URL to resolve from.
395  **Default:** `import.meta.url`
396
397## Interoperability with CommonJS
398
399### `import` statements
400
401An `import` statement can reference an ES module or a CommonJS module.
402`import` statements are permitted only in ES modules, but dynamic [`import()`][]
403expressions are supported in CommonJS for loading ES modules.
404
405When importing [CommonJS modules](#commonjs-namespaces), the
406`module.exports` object is provided as the default export. Named exports may be
407available, provided by static analysis as a convenience for better ecosystem
408compatibility.
409
410### `require`
411
412The CommonJS module `require` always treats the files it references as CommonJS.
413
414Using `require` to load an ES module is not supported because ES modules have
415asynchronous execution. Instead, use [`import()`][] to load an ES module
416from a CommonJS module.
417
418### CommonJS Namespaces
419
420CommonJS modules consist of a `module.exports` object which can be of any type.
421
422When importing a CommonJS module, it can be reliably imported using the ES
423module default import or its corresponding sugar syntax:
424
425<!-- eslint-disable no-duplicate-imports -->
426
427```js
428import { default as cjs } from 'cjs';
429
430// The following import statement is "syntax sugar" (equivalent but sweeter)
431// for `{ default as cjsSugar }` in the above import statement:
432import cjsSugar from 'cjs';
433
434console.log(cjs);
435console.log(cjs === cjsSugar);
436// Prints:
437//   <module.exports>
438//   true
439```
440
441The ECMAScript Module Namespace representation of a CommonJS module is always
442a namespace with a `default` export key pointing to the CommonJS
443`module.exports` value.
444
445This Module Namespace Exotic Object can be directly observed either when using
446`import * as m from 'cjs'` or a dynamic import:
447
448<!-- eslint-skip -->
449
450```js
451import * as m from 'cjs';
452console.log(m);
453console.log(m === await import('cjs'));
454// Prints:
455//   [Module] { default: <module.exports> }
456//   true
457```
458
459For better compatibility with existing usage in the JS ecosystem, Node.js
460in addition attempts to determine the CommonJS named exports of every imported
461CommonJS module to provide them as separate ES module exports using a static
462analysis process.
463
464For example, consider a CommonJS module written:
465
466```cjs
467// cjs.cjs
468exports.name = 'exported';
469```
470
471The preceding module supports named imports in ES modules:
472
473<!-- eslint-disable no-duplicate-imports -->
474
475```js
476import { name } from './cjs.cjs';
477console.log(name);
478// Prints: 'exported'
479
480import cjs from './cjs.cjs';
481console.log(cjs);
482// Prints: { name: 'exported' }
483
484import * as m from './cjs.cjs';
485console.log(m);
486// Prints: [Module] { default: { name: 'exported' }, name: 'exported' }
487```
488
489As can be seen from the last example of the Module Namespace Exotic Object being
490logged, the `name` export is copied off of the `module.exports` object and set
491directly on the ES module namespace when the module is imported.
492
493Live binding updates or new exports added to `module.exports` are not detected
494for these named exports.
495
496The detection of named exports is based on common syntax patterns but does not
497always correctly detect named exports. In these cases, using the default
498import form described above can be a better option.
499
500Named exports detection covers many common export patterns, reexport patterns
501and build tool and transpiler outputs. See [cjs-module-lexer][] for the exact
502semantics implemented.
503
504### Differences between ES modules and CommonJS
505
506#### No `require`, `exports`, or `module.exports`
507
508In most cases, the ES module `import` can be used to load CommonJS modules.
509
510If needed, a `require` function can be constructed within an ES module using
511[`module.createRequire()`][].
512
513#### No `__filename` or `__dirname`
514
515These CommonJS variables are not available in ES modules.
516
517`__filename` and `__dirname` use cases can be replicated via
518[`import.meta.url`][].
519
520#### No Addon Loading
521
522[Addons][] are not currently supported with ES module imports.
523
524They can instead be loaded with [`module.createRequire()`][] or
525[`process.dlopen`][].
526
527#### No `require.resolve`
528
529Relative resolution can be handled via `new URL('./local', import.meta.url)`.
530
531For a complete `require.resolve` replacement, there is the
532[import.meta.resolve][] API.
533
534Alternatively `module.createRequire()` can be used.
535
536#### No `NODE_PATH`
537
538`NODE_PATH` is not part of resolving `import` specifiers. Please use symlinks
539if this behavior is desired.
540
541#### No `require.extensions`
542
543`require.extensions` is not used by `import`. Module customization hooks can
544provide a replacement.
545
546#### No `require.cache`
547
548`require.cache` is not used by `import` as the ES module loader has its own
549separate cache.
550
551<i id="esm_experimental_json_modules"></i>
552
553## JSON modules
554
555> Stability: 1 - Experimental
556
557JSON files can be referenced by `import`:
558
559```js
560import packageConfig from './package.json' with { type: 'json' };
561```
562
563The `with { type: 'json' }` syntax is mandatory; see [Import Attributes][].
564
565The imported JSON only exposes a `default` export. There is no support for named
566exports. A cache entry is created in the CommonJS cache to avoid duplication.
567The same object is returned in CommonJS if the JSON module has already been
568imported from the same path.
569
570<i id="esm_experimental_wasm_modules"></i>
571
572## Wasm modules
573
574> Stability: 1 - Experimental
575
576Importing WebAssembly modules is supported under the
577`--experimental-wasm-modules` flag, allowing any `.wasm` files to be
578imported as normal modules while also supporting their module imports.
579
580This integration is in line with the
581[ES Module Integration Proposal for WebAssembly][].
582
583For example, an `index.mjs` containing:
584
585```js
586import * as M from './module.wasm';
587console.log(M);
588```
589
590executed under:
591
592```bash
593node --experimental-wasm-modules index.mjs
594```
595
596would provide the exports interface for the instantiation of `module.wasm`.
597
598<i id="esm_experimental_top_level_await"></i>
599
600## Top-level `await`
601
602<!-- YAML
603added: v14.8.0
604-->
605
606The `await` keyword may be used in the top level body of an ECMAScript module.
607
608Assuming an `a.mjs` with
609
610```js
611export const five = await Promise.resolve(5);
612```
613
614And a `b.mjs` with
615
616```js
617import { five } from './a.mjs';
618
619console.log(five); // Logs `5`
620```
621
622```bash
623node b.mjs # works
624```
625
626If a top level `await` expression never resolves, the `node` process will exit
627with a `13` [status code][].
628
629```js
630import { spawn } from 'node:child_process';
631import { execPath } from 'node:process';
632
633spawn(execPath, [
634  '--input-type=module',
635  '--eval',
636  // Never-resolving Promise:
637  'await new Promise(() => {})',
638]).once('exit', (code) => {
639  console.log(code); // Logs `13`
640});
641```
642
643## HTTPS and HTTP imports
644
645> Stability: 1 - Experimental
646
647Importing network based modules using `https:` and `http:` is supported under
648the `--experimental-network-imports` flag. This allows web browser-like imports
649to work in Node.js with a few differences due to application stability and
650security concerns that are different when running in a privileged environment
651instead of a browser sandbox.
652
653### Imports are limited to HTTP/1
654
655Automatic protocol negotiation for HTTP/2 and HTTP/3 is not yet supported.
656
657### HTTP is limited to loopback addresses
658
659`http:` is vulnerable to man-in-the-middle attacks and is not allowed to be
660used for addresses outside of the IPv4 address `127.0.0.0/8` (`127.0.0.1` to
661`127.255.255.255`) and the IPv6 address `::1`. Support for `http:` is intended
662to be used for local development.
663
664### Authentication is never sent to the destination server.
665
666`Authorization`, `Cookie`, and `Proxy-Authorization` headers are not sent to the
667server. Avoid including user info in parts of imported URLs. A security model
668for safely using these on the server is being worked on.
669
670### CORS is never checked on the destination server
671
672CORS is designed to allow a server to limit the consumers of an API to a
673specific set of hosts. This is not supported as it does not make sense for a
674server-based implementation.
675
676### Cannot load non-network dependencies
677
678These modules cannot access other modules that are not over `http:` or `https:`.
679To still access local modules while avoiding the security concern, pass in
680references to the local dependencies:
681
682```mjs
683// file.mjs
684import worker_threads from 'node:worker_threads';
685import { configure, resize } from 'https://example.com/imagelib.mjs';
686configure({ worker_threads });
687```
688
689```mjs
690// https://example.com/imagelib.mjs
691let worker_threads;
692export function configure(opts) {
693  worker_threads = opts.worker_threads;
694}
695export function resize(img, size) {
696  // Perform resizing in worker_thread to avoid main thread blocking
697}
698```
699
700### Network-based loading is not enabled by default
701
702For now, the `--experimental-network-imports` flag is required to enable loading
703resources over `http:` or `https:`. In the future, a different mechanism will be
704used to enforce this. Opt-in is required to prevent transitive dependencies
705inadvertently using potentially mutable state that could affect reliability
706of Node.js applications.
707
708<i id="esm_experimental_loaders"></i>
709
710## Loaders
711
712The former Loaders documentation is now at
713[Modules: Customization hooks][Module customization hooks].
714
715## Resolution and loading algorithm
716
717### Features
718
719The default resolver has the following properties:
720
721* FileURL-based resolution as is used by ES modules
722* Relative and absolute URL resolution
723* No default extensions
724* No folder mains
725* Bare specifier package resolution lookup through node\_modules
726* Does not fail on unknown extensions or protocols
727* Can optionally provide a hint of the format to the loading phase
728
729The default loader has the following properties
730
731* Support for builtin module loading via `node:` URLs
732* Support for "inline" module loading via `data:` URLs
733* Support for `file:` module loading
734* Fails on any other URL protocol
735* Fails on unknown extensions for `file:` loading
736  (supports only `.cjs`, `.js`, and `.mjs`)
737
738### Resolution algorithm
739
740The algorithm to load an ES module specifier is given through the
741**ESM\_RESOLVE** method below. It returns the resolved URL for a
742module specifier relative to a parentURL.
743
744The resolution algorithm determines the full resolved URL for a module
745load, along with its suggested module format. The resolution algorithm
746does not determine whether the resolved URL protocol can be loaded,
747or whether the file extensions are permitted, instead these validations
748are applied by Node.js during the load phase
749(for example, if it was asked to load a URL that has a protocol that is
750not `file:`, `data:`, `node:`, or if `--experimental-network-imports`
751is enabled, `https:`).
752
753The algorithm also tries to determine the format of the file based
754on the extension (see `ESM_FILE_FORMAT` algorithm below). If it does
755not recognize the file extension (eg if it is not `.mjs`, `.cjs`, or
756`.json`), then a format of `undefined` is returned,
757which will throw during the load phase.
758
759The algorithm to determine the module format of a resolved URL is
760provided by **ESM\_FILE\_FORMAT**, which returns the unique module
761format for any file. The _"module"_ format is returned for an ECMAScript
762Module, while the _"commonjs"_ format is used to indicate loading through the
763legacy CommonJS loader. Additional formats such as _"addon"_ can be extended in
764future updates.
765
766In the following algorithms, all subroutine errors are propagated as errors
767of these top-level routines unless stated otherwise.
768
769_defaultConditions_ is the conditional environment name array,
770`["node", "import"]`.
771
772The resolver can throw the following errors:
773
774* _Invalid Module Specifier_: Module specifier is an invalid URL, package name
775  or package subpath specifier.
776* _Invalid Package Configuration_: package.json configuration is invalid or
777  contains an invalid configuration.
778* _Invalid Package Target_: Package exports or imports define a target module
779  for the package that is an invalid type or string target.
780* _Package Path Not Exported_: Package exports do not define or permit a target
781  subpath in the package for the given module.
782* _Package Import Not Defined_: Package imports do not define the specifier.
783* _Module Not Found_: The package or module requested does not exist.
784* _Unsupported Directory Import_: The resolved path corresponds to a directory,
785  which is not a supported target for module imports.
786
787### Resolution Algorithm Specification
788
789**ESM\_RESOLVE**(_specifier_, _parentURL_)
790
791> 1. Let _resolved_ be **undefined**.
792> 2. If _specifier_ is a valid URL, then
793>    1. Set _resolved_ to the result of parsing and reserializing
794>       _specifier_ as a URL.
795> 3. Otherwise, if _specifier_ starts with _"/"_, _"./"_, or _"../"_, then
796>    1. Set _resolved_ to the URL resolution of _specifier_ relative to
797>       _parentURL_.
798> 4. Otherwise, if _specifier_ starts with _"#"_, then
799>    1. Set _resolved_ to the result of
800>       **PACKAGE\_IMPORTS\_RESOLVE**(_specifier_,
801>       _parentURL_, _defaultConditions_).
802> 5. Otherwise,
803>    1. Note: _specifier_ is now a bare specifier.
804>    2. Set _resolved_ the result of
805>       **PACKAGE\_RESOLVE**(_specifier_, _parentURL_).
806> 6. Let _format_ be **undefined**.
807> 7. If _resolved_ is a _"file:"_ URL, then
808>    1. If _resolved_ contains any percent encodings of _"/"_ or _"\\"_ (_"%2F"_
809>       and _"%5C"_ respectively), then
810>       1. Throw an _Invalid Module Specifier_ error.
811>    2. If the file at _resolved_ is a directory, then
812>       1. Throw an _Unsupported Directory Import_ error.
813>    3. If the file at _resolved_ does not exist, then
814>       1. Throw a _Module Not Found_ error.
815>    4. Set _resolved_ to the real path of _resolved_, maintaining the
816>       same URL querystring and fragment components.
817>    5. Set _format_ to the result of **ESM\_FILE\_FORMAT**(_resolved_).
818> 8. Otherwise,
819>    1. Set _format_ the module format of the content type associated with the
820>       URL _resolved_.
821> 9. Return _format_ and _resolved_ to the loading phase
822
823**PACKAGE\_RESOLVE**(_packageSpecifier_, _parentURL_)
824
825> 1. Let _packageName_ be **undefined**.
826> 2. If _packageSpecifier_ is an empty string, then
827>    1. Throw an _Invalid Module Specifier_ error.
828> 3. If _packageSpecifier_ is a Node.js builtin module name, then
829>    1. Return the string _"node:"_ concatenated with _packageSpecifier_.
830> 4. If _packageSpecifier_ does not start with _"@"_, then
831>    1. Set _packageName_ to the substring of _packageSpecifier_ until the first
832>       _"/"_ separator or the end of the string.
833> 5. Otherwise,
834>    1. If _packageSpecifier_ does not contain a _"/"_ separator, then
835>       1. Throw an _Invalid Module Specifier_ error.
836>    2. Set _packageName_ to the substring of _packageSpecifier_
837>       until the second _"/"_ separator or the end of the string.
838> 6. If _packageName_ starts with _"."_ or contains _"\\"_ or _"%"_, then
839>    1. Throw an _Invalid Module Specifier_ error.
840> 7. Let _packageSubpath_ be _"."_ concatenated with the substring of
841>    _packageSpecifier_ from the position at the length of _packageName_.
842> 8. If _packageSubpath_ ends in _"/"_, then
843>    1. Throw an _Invalid Module Specifier_ error.
844> 9. Let _selfUrl_ be the result of
845>    **PACKAGE\_SELF\_RESOLVE**(_packageName_, _packageSubpath_, _parentURL_).
846> 10. If _selfUrl_ is not **undefined**, return _selfUrl_.
847> 11. While _parentURL_ is not the file system root,
848>     1. Let _packageURL_ be the URL resolution of _"node\_modules/"_
849>        concatenated with _packageSpecifier_, relative to _parentURL_.
850>     2. Set _parentURL_ to the parent folder URL of _parentURL_.
851>     3. If the folder at _packageURL_ does not exist, then
852>        1. Continue the next loop iteration.
853>     4. Let _pjson_ be the result of **READ\_PACKAGE\_JSON**(_packageURL_).
854>     5. If _pjson_ is not **null** and _pjson_._exports_ is not **null** or
855>        **undefined**, then
856>        1. Return the result of **PACKAGE\_EXPORTS\_RESOLVE**(_packageURL_,
857>           _packageSubpath_, _pjson.exports_, _defaultConditions_).
858>     6. Otherwise, if _packageSubpath_ is equal to _"."_, then
859>        1. If _pjson.main_ is a string, then
860>           1. Return the URL resolution of _main_ in _packageURL_.
861>     7. Otherwise,
862>        1. Return the URL resolution of _packageSubpath_ in _packageURL_.
863> 12. Throw a _Module Not Found_ error.
864
865**PACKAGE\_SELF\_RESOLVE**(_packageName_, _packageSubpath_, _parentURL_)
866
867> 1. Let _packageURL_ be the result of **LOOKUP\_PACKAGE\_SCOPE**(_parentURL_).
868> 2. If _packageURL_ is **null**, then
869>    1. Return **undefined**.
870> 3. Let _pjson_ be the result of **READ\_PACKAGE\_JSON**(_packageURL_).
871> 4. If _pjson_ is **null** or if _pjson_._exports_ is **null** or
872>    **undefined**, then
873>    1. Return **undefined**.
874> 5. If _pjson.name_ is equal to _packageName_, then
875>    1. Return the result of **PACKAGE\_EXPORTS\_RESOLVE**(_packageURL_,
876>       _packageSubpath_, _pjson.exports_, _defaultConditions_).
877> 6. Otherwise, return **undefined**.
878
879**PACKAGE\_EXPORTS\_RESOLVE**(_packageURL_, _subpath_, _exports_, _conditions_)
880
881> 1. If _exports_ is an Object with both a key starting with _"."_ and a key not
882>    starting with _"."_, throw an _Invalid Package Configuration_ error.
883> 2. If _subpath_ is equal to _"."_, then
884>    1. Let _mainExport_ be **undefined**.
885>    2. If _exports_ is a String or Array, or an Object containing no keys
886>       starting with _"."_, then
887>       1. Set _mainExport_ to _exports_.
888>    3. Otherwise if _exports_ is an Object containing a _"."_ property, then
889>       1. Set _mainExport_ to _exports_\[_"."_].
890>    4. If _mainExport_ is not **undefined**, then
891>       1. Let _resolved_ be the result of **PACKAGE\_TARGET\_RESOLVE**(
892>          _packageURL_, _mainExport_, **null**, **false**, _conditions_).
893>       2. If _resolved_ is not **null** or **undefined**, return _resolved_.
894> 3. Otherwise, if _exports_ is an Object and all keys of _exports_ start with
895>    _"."_, then
896>    1. Let _matchKey_ be the string _"./"_ concatenated with _subpath_.
897>    2. Let _resolved_ be the result of **PACKAGE\_IMPORTS\_EXPORTS\_RESOLVE**(
898>       _matchKey_, _exports_, _packageURL_, **false**, _conditions_).
899>    3. If _resolved_ is not **null** or **undefined**, return _resolved_.
900> 4. Throw a _Package Path Not Exported_ error.
901
902**PACKAGE\_IMPORTS\_RESOLVE**(_specifier_, _parentURL_, _conditions_)
903
904> 1. Assert: _specifier_ begins with _"#"_.
905> 2. If _specifier_ is exactly equal to _"#"_ or starts with _"#/"_, then
906>    1. Throw an _Invalid Module Specifier_ error.
907> 3. Let _packageURL_ be the result of **LOOKUP\_PACKAGE\_SCOPE**(_parentURL_).
908> 4. If _packageURL_ is not **null**, then
909>    1. Let _pjson_ be the result of **READ\_PACKAGE\_JSON**(_packageURL_).
910>    2. If _pjson.imports_ is a non-null Object, then
911>       1. Let _resolved_ be the result of
912>          **PACKAGE\_IMPORTS\_EXPORTS\_RESOLVE**(
913>          _specifier_, _pjson.imports_, _packageURL_, **true**, _conditions_).
914>       2. If _resolved_ is not **null** or **undefined**, return _resolved_.
915> 5. Throw a _Package Import Not Defined_ error.
916
917**PACKAGE\_IMPORTS\_EXPORTS\_RESOLVE**(_matchKey_, _matchObj_, _packageURL_,
918_isImports_, _conditions_)
919
920> 1. If _matchKey_ is a key of _matchObj_ and does not contain _"\*"_, then
921>    1. Let _target_ be the value of _matchObj_\[_matchKey_].
922>    2. Return the result of **PACKAGE\_TARGET\_RESOLVE**(_packageURL_,
923>       _target_, **null**, _isImports_, _conditions_).
924> 2. Let _expansionKeys_ be the list of keys of _matchObj_ containing only a
925>    single _"\*"_, sorted by the sorting function **PATTERN\_KEY\_COMPARE**
926>    which orders in descending order of specificity.
927> 3. For each key _expansionKey_ in _expansionKeys_, do
928>    1. Let _patternBase_ be the substring of _expansionKey_ up to but excluding
929>       the first _"\*"_ character.
930>    2. If _matchKey_ starts with but is not equal to _patternBase_, then
931>       1. Let _patternTrailer_ be the substring of _expansionKey_ from the
932>          index after the first _"\*"_ character.
933>       2. If _patternTrailer_ has zero length, or if _matchKey_ ends with
934>          _patternTrailer_ and the length of _matchKey_ is greater than or
935>          equal to the length of _expansionKey_, then
936>          1. Let _target_ be the value of _matchObj_\[_expansionKey_].
937>          2. Let _patternMatch_ be the substring of _matchKey_ starting at the
938>             index of the length of _patternBase_ up to the length of
939>             _matchKey_ minus the length of _patternTrailer_.
940>          3. Return the result of **PACKAGE\_TARGET\_RESOLVE**(_packageURL_,
941>             _target_, _patternMatch_, _isImports_, _conditions_).
942> 4. Return **null**.
943
944**PATTERN\_KEY\_COMPARE**(_keyA_, _keyB_)
945
946> 1. Assert: _keyA_ ends with _"/"_ or contains only a single _"\*"_.
947> 2. Assert: _keyB_ ends with _"/"_ or contains only a single _"\*"_.
948> 3. Let _baseLengthA_ be the index of _"\*"_ in _keyA_ plus one, if _keyA_
949>    contains _"\*"_, or the length of _keyA_ otherwise.
950> 4. Let _baseLengthB_ be the index of _"\*"_ in _keyB_ plus one, if _keyB_
951>    contains _"\*"_, or the length of _keyB_ otherwise.
952> 5. If _baseLengthA_ is greater than _baseLengthB_, return -1.
953> 6. If _baseLengthB_ is greater than _baseLengthA_, return 1.
954> 7. If _keyA_ does not contain _"\*"_, return 1.
955> 8. If _keyB_ does not contain _"\*"_, return -1.
956> 9. If the length of _keyA_ is greater than the length of _keyB_, return -1.
957> 10. If the length of _keyB_ is greater than the length of _keyA_, return 1.
958> 11. Return 0.
959
960**PACKAGE\_TARGET\_RESOLVE**(_packageURL_, _target_, _patternMatch_,
961_isImports_, _conditions_)
962
963> 1. If _target_ is a String, then
964>    1. If _target_ does not start with _"./"_, then
965>       1. If _isImports_ is **false**, or if _target_ starts with _"../"_ or
966>          _"/"_, or if _target_ is a valid URL, then
967>          1. Throw an _Invalid Package Target_ error.
968>       2. If _patternMatch_ is a String, then
969>          1. Return **PACKAGE\_RESOLVE**(_target_ with every instance of _"\*"_
970>             replaced by _patternMatch_, _packageURL_ + _"/"_).
971>       3. Return **PACKAGE\_RESOLVE**(_target_, _packageURL_ + _"/"_).
972>    2. If _target_ split on _"/"_ or _"\\"_ contains any _""_, _"."_, _".."_,
973>       or _"node\_modules"_ segments after the first _"."_ segment, case
974>       insensitive and including percent encoded variants, throw an _Invalid
975>       Package Target_ error.
976>    3. Let _resolvedTarget_ be the URL resolution of the concatenation of
977>       _packageURL_ and _target_.
978>    4. Assert: _resolvedTarget_ is contained in _packageURL_.
979>    5. If _patternMatch_ is **null**, then
980>       1. Return _resolvedTarget_.
981>    6. If _patternMatch_ split on _"/"_ or _"\\"_ contains any _""_, _"."_,
982>       _".."_, or _"node\_modules"_ segments, case insensitive and including
983>       percent encoded variants, throw an _Invalid Module Specifier_ error.
984>    7. Return the URL resolution of _resolvedTarget_ with every instance of
985>       _"\*"_ replaced with _patternMatch_.
986> 2. Otherwise, if _target_ is a non-null Object, then
987>    1. If _exports_ contains any index property keys, as defined in ECMA-262
988>       [6.1.7 Array Index][], throw an _Invalid Package Configuration_ error.
989>    2. For each property _p_ of _target_, in object insertion order as,
990>       1. If _p_ equals _"default"_ or _conditions_ contains an entry for _p_,
991>          then
992>          1. Let _targetValue_ be the value of the _p_ property in _target_.
993>          2. Let _resolved_ be the result of **PACKAGE\_TARGET\_RESOLVE**(
994>             _packageURL_, _targetValue_, _patternMatch_, _isImports_,
995>             _conditions_).
996>          3. If _resolved_ is equal to **undefined**, continue the loop.
997>          4. Return _resolved_.
998>    3. Return **undefined**.
999> 3. Otherwise, if _target_ is an Array, then
1000>    1. If \_target.length is zero, return **null**.
1001>    2. For each item _targetValue_ in _target_, do
1002>       1. Let _resolved_ be the result of **PACKAGE\_TARGET\_RESOLVE**(
1003>          _packageURL_, _targetValue_, _patternMatch_, _isImports_,
1004>          _conditions_), continuing the loop on any _Invalid Package Target_
1005>          error.
1006>       2. If _resolved_ is **undefined**, continue the loop.
1007>       3. Return _resolved_.
1008>    3. Return or throw the last fallback resolution **null** return or error.
1009> 4. Otherwise, if _target_ is _null_, return **null**.
1010> 5. Otherwise throw an _Invalid Package Target_ error.
1011
1012**ESM\_FILE\_FORMAT**(_url_)
1013
1014> 1. Assert: _url_ corresponds to an existing file.
1015> 2. If _url_ ends in _".mjs"_, then
1016>    1. Return _"module"_.
1017> 3. If _url_ ends in _".cjs"_, then
1018>    1. Return _"commonjs"_.
1019> 4. If _url_ ends in _".json"_, then
1020>    1. Return _"json"_.
1021> 5. Let _packageURL_ be the result of **LOOKUP\_PACKAGE\_SCOPE**(_url_).
1022> 6. Let _pjson_ be the result of **READ\_PACKAGE\_JSON**(_packageURL_).
1023> 7. If _pjson?.type_ exists and is _"module"_, then
1024>    1. If _url_ ends in _".js"_ or has no file extension, then
1025>       1. If `--experimental-wasm-modules` is enabled and the file at _url_
1026>          contains the header for a WebAssembly module, then
1027>          1. Return _"wasm"_.
1028>       2. Otherwise,
1029>          1. Return _"module"_.
1030>    2. Return **undefined**.
1031> 8. Otherwise,
1032>    1. Return **undefined**.
1033
1034**LOOKUP\_PACKAGE\_SCOPE**(_url_)
1035
1036> 1. Let _scopeURL_ be _url_.
1037> 2. While _scopeURL_ is not the file system root,
1038>    1. Set _scopeURL_ to the parent URL of _scopeURL_.
1039>    2. If _scopeURL_ ends in a _"node\_modules"_ path segment, return **null**.
1040>    3. Let _pjsonURL_ be the resolution of _"package.json"_ within
1041>       _scopeURL_.
1042>    4. if the file at _pjsonURL_ exists, then
1043>       1. Return _scopeURL_.
1044> 3. Return **null**.
1045
1046**READ\_PACKAGE\_JSON**(_packageURL_)
1047
1048> 1. Let _pjsonURL_ be the resolution of _"package.json"_ within _packageURL_.
1049> 2. If the file at _pjsonURL_ does not exist, then
1050>    1. Return **null**.
1051> 3. If the file at _packageURL_ does not parse as valid JSON, then
1052>    1. Throw an _Invalid Package Configuration_ error.
1053> 4. Return the parsed JSON source of the file at _pjsonURL_.
1054
1055### Customizing ESM specifier resolution algorithm
1056
1057> Stability: 1 - Experimental
1058
1059> Do not rely on this flag. We plan to remove it once the
1060> [Module customization hooks][] have advanced to the point that equivalent
1061> functionality can be achieved via custom hooks.
1062
1063The current specifier resolution does not support all default behavior of
1064the CommonJS loader. One of the behavior differences is automatic resolution
1065of file extensions and the ability to import directories that have an index
1066file.
1067
1068The `--experimental-specifier-resolution=[mode]` flag can be used to customize
1069the extension resolution algorithm. The default mode is `explicit`, which
1070requires the full path to a module be provided to the loader. To enable the
1071automatic extension resolution and importing from directories that include an
1072index file use the `node` mode.
1073
1074```console
1075$ node index.mjs
1076success!
1077$ node index # Failure!
1078Error: Cannot find module
1079$ node --experimental-specifier-resolution=node index
1080success!
1081```
1082
1083<!-- Note: The cjs-module-lexer link should be kept in-sync with the deps version -->
1084
1085[6.1.7 Array Index]: https://tc39.es/ecma262/#integer-index
1086[Addons]: addons.md
1087[CommonJS]: modules.md
1088[Core modules]: modules.md#core-modules
1089[Determining module system]: packages.md#determining-module-system
1090[Dynamic `import()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import
1091[ES Module Integration Proposal for WebAssembly]: https://github.com/webassembly/esm-integration
1092[Import Attributes]: #import-attributes
1093[Import Attributes proposal]: https://github.com/tc39/proposal-import-attributes
1094[JSON modules]: #json-modules
1095[Module customization hooks]: module.md#customization-hooks
1096[Node.js Module Resolution And Loading Algorithm]: #resolution-algorithm-specification
1097[Terminology]: #terminology
1098[URL]: https://url.spec.whatwg.org/
1099[`"exports"`]: packages.md#exports
1100[`"type"`]: packages.md#type
1101[`--experimental-default-type`]: cli.md#--experimental-default-typetype
1102[`--input-type`]: cli.md#--input-typetype
1103[`data:` URLs]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs
1104[`export`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export
1105[`import()`]: #import-expressions
1106[`import.meta.resolve`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import.meta/resolve
1107[`import.meta.url`]: #importmetaurl
1108[`import`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import
1109[`module.createRequire()`]: module.md#modulecreaterequirefilename
1110[`module.syncBuiltinESMExports()`]: module.md#modulesyncbuiltinesmexports
1111[`package.json`]: packages.md#nodejs-packagejson-field-definitions
1112[`process.dlopen`]: process.md#processdlopenmodule-filename-flags
1113[cjs-module-lexer]: https://github.com/nodejs/cjs-module-lexer/tree/1.2.2
1114[custom https loader]: module.md#import-from-https
1115[import.meta.resolve]: #importmetaresolvespecifier
1116[percent-encoded]: url.md#percent-encoding-in-urls
1117[special scheme]: https://url.spec.whatwg.org/#special-scheme
1118[status code]: process.md#exit-codes
1119[the official standard format]: https://tc39.github.io/ecma262/#sec-modules
1120[url.pathToFileURL]: url.md#urlpathtofileurlpath
1121