1# Modules: Packages 2 3<!-- type=misc --> 4<!-- YAML 5changes: 6 - version: v12.20.0 7 pr-url: https://github.com/nodejs/node/pull/34718 8 description: Add support for `"exports"` patterns. 9 - version: v12.19.0 10 pr-url: https://github.com/nodejs/node/pull/34117 11 description: Add package `"imports"` field. 12 - version: 13 - v12.16.0 14 pr-url: https://github.com/nodejs/node/pull/31001 15 description: Unflag conditional exports. 16 - version: 17 - v12.16.0 18 pr-url: https://github.com/nodejs/node/pull/31002 19 description: Unflag self-referencing a package using its name. 20 - version: v12.7.0 21 pr-url: https://github.com/nodejs/node/pull/28568 22 description: 23 Introduce `"exports"` `package.json` field as a more powerful alternative 24 to the classic `"main"` field. 25 - version: v12.0.0 26 pr-url: https://github.com/nodejs/node/pull/26745 27 description: 28 Add support for ES modules using `.js` file extension via `package.json` 29 `"type"` field. 30--> 31 32## Introduction 33 34A package is a folder tree described by a `package.json` file. The package 35consists of the folder containing the `package.json` file and all subfolders 36until the next folder containing another `package.json` file, or a folder 37named `node_modules`. 38 39This page provides guidance for package authors writing `package.json` files 40along with a reference for the [`package.json`][] fields defined by Node.js. 41 42## Determining module system 43 44Node.js will treat the following as [ES modules][] when passed to `node` as the 45initial input, or when referenced by `import` statements within ES module code: 46 47* Files ending in `.mjs`. 48 49* Files ending in `.js` when the nearest parent `package.json` file contains a 50 top-level [`"type"`][] field with a value of `"module"`. 51 52* Strings passed in as an argument to `--eval`, or piped to `node` via `STDIN`, 53 with the flag `--input-type=module`. 54 55Node.js will treat as [CommonJS][] all other forms of input, such as `.js` files 56where the nearest parent `package.json` file contains no top-level `"type"` 57field, or string input without the flag `--input-type`. This behavior is to 58preserve backward compatibility. However, now that Node.js supports both 59CommonJS and ES modules, it is best to be explicit whenever possible. Node.js 60will treat the following as CommonJS when passed to `node` as the initial input, 61or when referenced by `import` statements within ES module code: 62 63* Files ending in `.cjs`. 64 65* Files ending in `.js` when the nearest parent `package.json` file contains a 66 top-level field [`"type"`][] with a value of `"commonjs"`. 67 68* Strings passed in as an argument to `--eval` or `--print`, or piped to `node` 69 via `STDIN`, with the flag `--input-type=commonjs`. 70 71Package authors should include the [`"type"`][] field, even in packages where 72all sources are CommonJS. Being explicit about the `type` of the package will 73future-proof the package in case the default type of Node.js ever changes, and 74it will also make things easier for build tools and loaders to determine how the 75files in the package should be interpreted. 76 77### `package.json` and file extensions 78 79Within a package, the [`package.json`][] [`"type"`][] field defines how 80Node.js should interpret `.js` files. If a `package.json` file does not have a 81`"type"` field, `.js` files are treated as [CommonJS][]. 82 83A `package.json` `"type"` value of `"module"` tells Node.js to interpret `.js` 84files within that package as using [ES module][] syntax. 85 86The `"type"` field applies not only to initial entry points (`node my-app.js`) 87but also to files referenced by `import` statements and `import()` expressions. 88 89```js 90// my-app.js, treated as an ES module because there is a package.json 91// file in the same folder with "type": "module". 92 93import './startup/init.js'; 94// Loaded as ES module since ./startup contains no package.json file, 95// and therefore inherits the "type" value from one level up. 96 97import 'commonjs-package'; 98// Loaded as CommonJS since ./node_modules/commonjs-package/package.json 99// lacks a "type" field or contains "type": "commonjs". 100 101import './node_modules/commonjs-package/index.js'; 102// Loaded as CommonJS since ./node_modules/commonjs-package/package.json 103// lacks a "type" field or contains "type": "commonjs". 104``` 105 106Files ending with `.mjs` are always loaded as [ES modules][] regardless of 107the nearest parent `package.json`. 108 109Files ending with `.cjs` are always loaded as [CommonJS][] regardless of the 110nearest parent `package.json`. 111 112```js 113import './legacy-file.cjs'; 114// Loaded as CommonJS since .cjs is always loaded as CommonJS. 115 116import 'commonjs-package/src/index.mjs'; 117// Loaded as ES module since .mjs is always loaded as ES module. 118``` 119 120The `.mjs` and `.cjs` extensions can be used to mix types within the same 121package: 122 123* Within a `"type": "module"` package, Node.js can be instructed to 124 interpret a particular file as [CommonJS][] by naming it with a `.cjs` 125 extension (since both `.js` and `.mjs` files are treated as ES modules within 126 a `"module"` package). 127 128* Within a `"type": "commonjs"` package, Node.js can be instructed to 129 interpret a particular file as an [ES module][] by naming it with an `.mjs` 130 extension (since both `.js` and `.cjs` files are treated as CommonJS within a 131 `"commonjs"` package). 132 133### `--input-type` flag 134 135Strings passed in as an argument to `--eval` (or `-e`), or piped to `node` via 136`STDIN`, are treated as [ES modules][] when the `--input-type=module` flag 137is set. 138 139```bash 140node --input-type=module --eval "import { sep } from 'path'; console.log(sep);" 141 142echo "import { sep } from 'path'; console.log(sep);" | node --input-type=module 143``` 144 145For completeness there is also `--input-type=commonjs`, for explicitly running 146string input as CommonJS. This is the default behavior if `--input-type` is 147unspecified. 148 149## Package entry points 150 151In a package’s `package.json` file, two fields can define entry points for a 152package: [`"main"`][] and [`"exports"`][]. The [`"main"`][] field is supported 153in all versions of Node.js, but its capabilities are limited: it only defines 154the main entry point of the package. 155 156The [`"exports"`][] field provides an alternative to [`"main"`][] where the 157package main entry point can be defined while also encapsulating the package, 158**preventing any other entry points besides those defined in [`"exports"`][]**. 159This encapsulation allows module authors to define a public interface for 160their package. 161 162If both [`"exports"`][] and [`"main"`][] are defined, the [`"exports"`][] field 163takes precedence over [`"main"`][]. [`"exports"`][] are not specific to ES 164modules or CommonJS; [`"main"`][] is overridden by [`"exports"`][] if it 165exists. As such [`"main"`][] cannot be used as a fallback for CommonJS but it 166can be used as a fallback for legacy versions of Node.js that do not support the 167[`"exports"`][] field. 168 169[Conditional exports][] can be used within [`"exports"`][] to define different 170package entry points per environment, including whether the package is 171referenced via `require` or via `import`. For more information about supporting 172both CommonJS and ES Modules in a single package please consult 173[the dual CommonJS/ES module packages section][]. 174 175**Warning**: Introducing the [`"exports"`][] field prevents consumers of a 176package from using any entry points that are not defined, including the 177[`package.json`][] (e.g. `require('your-package/package.json')`. **This will 178likely be a breaking change.** 179 180To make the introduction of [`"exports"`][] non-breaking, ensure that every 181previously supported entry point is exported. It is best to explicitly specify 182entry points so that the package’s public API is well-defined. For example, 183a project that previous exported `main`, `lib`, 184`feature`, and the `package.json` could use the following `package.exports`: 185 186```json 187{ 188 "name": "my-mod", 189 "exports": { 190 ".": "./lib/index.js", 191 "./lib": "./lib/index.js", 192 "./lib/index": "./lib/index.js", 193 "./lib/index.js": "./lib/index.js", 194 "./feature": "./feature/index.js", 195 "./feature/index.js": "./feature/index.js", 196 "./package.json": "./package.json" 197 } 198} 199``` 200 201Alternatively a project could choose to export entire folders: 202 203```json 204{ 205 "name": "my-mod", 206 "exports": { 207 ".": "./lib/index.js", 208 "./lib": "./lib/index.js", 209 "./lib/*": "./lib/*.js", 210 "./feature": "./feature/index.js", 211 "./feature/*": "./feature/*.js", 212 "./package.json": "./package.json" 213 } 214} 215``` 216 217As a last resort, package encapsulation can be disabled entirely by creating an 218export for the root of the package `"./*": "./*"`. This exposes every file 219in the package at the cost of disabling the encapsulation and potential tooling 220benefits this provides. As the ES Module loader in Node.js enforces the use of 221[the full specifier path][], exporting the root rather than being explicit 222about entry is less expressive than either of the prior examples. Not only 223is encapsulation lost but module consumers are unable to 224`import feature from 'my-mod/feature'` as they need to provide the full 225path `import feature from 'my-mod/feature/index.js`. 226 227### Main entry point export 228 229To set the main entry point for a package, it is advisable to define both 230[`"exports"`][] and [`"main"`][] in the package’s [`package.json`][] file: 231 232```json 233{ 234 "main": "./main.js", 235 "exports": "./main.js" 236} 237``` 238 239When the [`"exports"`][] field is defined, all subpaths of the package are 240encapsulated and no longer available to importers. For example, 241`require('pkg/subpath.js')` throws an [`ERR_PACKAGE_PATH_NOT_EXPORTED`][] 242error. 243 244This encapsulation of exports provides more reliable guarantees 245about package interfaces for tools and when handling semver upgrades for a 246package. It is not a strong encapsulation since a direct require of any 247absolute subpath of the package such as 248`require('/path/to/node_modules/pkg/subpath.js')` will still load `subpath.js`. 249 250### Subpath exports 251 252> Stability: 1 - Experimental 253 254When using the [`"exports"`][] field, custom subpaths can be defined along 255with the main entry point by treating the main entry point as the 256`"."` subpath: 257 258```json 259{ 260 "main": "./main.js", 261 "exports": { 262 ".": "./main.js", 263 "./submodule": "./src/submodule.js" 264 } 265} 266``` 267 268Now only the defined subpath in [`"exports"`][] can be imported by a consumer: 269 270```js 271import submodule from 'es-module-package/submodule'; 272// Loads ./node_modules/es-module-package/src/submodule.js 273``` 274 275While other subpaths will error: 276 277```js 278import submodule from 'es-module-package/private-module.js'; 279// Throws ERR_PACKAGE_PATH_NOT_EXPORTED 280``` 281 282### Subpath imports 283 284> Stability: 1 - Experimental 285 286In addition to the [`"exports"`][] field, it is possible to define internal 287package import maps that only apply to import specifiers from within the package 288itself. 289 290Entries in the imports field must always start with `#` to ensure they are 291disambiguated from package specifiers. 292 293For example, the imports field can be used to gain the benefits of conditional 294exports for internal modules: 295 296```json 297// package.json 298{ 299 "imports": { 300 "#dep": { 301 "node": "dep-node-native", 302 "default": "./dep-polyfill.js" 303 } 304 }, 305 "dependencies": { 306 "dep-node-native": "^1.0.0" 307 } 308} 309``` 310 311where `import '#dep'` does not get the resolution of the external package 312`dep-node-native` (including its exports in turn), and instead gets the local 313file `./dep-polyfill.js` relative to the package in other environments. 314 315Unlike the `"exports"` field, the `"imports"` field permits mapping to external 316packages. 317 318The resolution rules for the imports field are otherwise 319analogous to the exports field. 320 321### Subpath patterns 322 323> Stability: 1 - Experimental 324 325For packages with a small number of exports or imports, we recommend 326explicitly listing each exports subpath entry. But for packages that have 327large numbers of subpaths, this might cause `package.json` bloat and 328maintenance issues. 329 330For these use cases, subpath export patterns can be used instead: 331 332```json 333// ./node_modules/es-module-package/package.json 334{ 335 "exports": { 336 "./features/*": "./src/features/*.js" 337 }, 338 "imports": { 339 "#internal/*": "./src/internal/*.js" 340 } 341} 342``` 343 344The left hand matching pattern must always end in `*`. All instances of `*` on 345the right hand side will then be replaced with this value, including if it 346contains any `/` separators. 347 348```js 349import featureX from 'es-module-package/features/x'; 350// Loads ./node_modules/es-module-package/src/features/x.js 351 352import featureY from 'es-module-package/features/y/y'; 353// Loads ./node_modules/es-module-package/src/features/y/y.js 354 355import internalZ from '#internal/z'; 356// Loads ./node_modules/es-module-package/src/internal/z.js 357``` 358 359This is a direct static replacement without any special handling for file 360extensions. In the previous example, `pkg/features/x.json` would be resolved to 361`./src/features/x.json.js` in the mapping. 362 363The property of exports being statically enumerable is maintained with exports 364patterns since the individual exports for a package can be determined by 365treating the right hand side target pattern as a `**` glob against the list of 366files within the package. Because `node_modules` paths are forbidden in exports 367targets, this expansion is dependent on only the files of the package itself. 368 369### Exports sugar 370 371> Stability: 1 - Experimental 372 373If the `"."` export is the only export, the [`"exports"`][] field provides sugar 374for this case being the direct [`"exports"`][] field value. 375 376If the `"."` export has a fallback array or string value, then the 377[`"exports"`][] field can be set to this value directly. 378 379```json 380{ 381 "exports": { 382 ".": "./main.js" 383 } 384} 385``` 386 387can be written: 388 389```json 390{ 391 "exports": "./main.js" 392} 393``` 394 395### Conditional exports 396 397> Stability: 1 - Experimental 398 399Conditional exports provide a way to map to different paths depending on 400certain conditions. They are supported for both CommonJS and ES module imports. 401 402For example, a package that wants to provide different ES module exports for 403`require()` and `import` can be written: 404 405```json 406// package.json 407{ 408 "main": "./main-require.cjs", 409 "exports": { 410 "import": "./main-module.js", 411 "require": "./main-require.cjs" 412 }, 413 "type": "module" 414} 415``` 416 417Node.js supports the following conditions out of the box: 418 419* `"import"` - matches when the package is loaded via `import` or 420 `import()`, or via any top-level import or resolve operation by the 421 ECMAScript module loader. Applies regardless of the module format of the 422 target file. _Always mutually exclusive with `"require"`._ 423* `"require"` - matches when the package is loaded via `require()`. The 424 referenced file should be loadable with `require()` although the condition 425 matches regardless of the module format of the target file. Expected 426 formats include CommonJS, JSON, and native addons but not ES modules as 427 `require()` doesn't support them. _Always mutually exclusive with 428 `"import"`._ 429* `"node"` - matches for any Node.js environment. Can be a CommonJS or ES 430 module file. _This condition should always come after `"import"` or 431 `"require"`._ 432* `"default"` - the generic fallback that always matches. Can be a CommonJS 433 or ES module file. _This condition should always come last._ 434 435Within the [`"exports"`][] object, key order is significant. During condition 436matching, earlier entries have higher priority and take precedence over later 437entries. _The general rule is that conditions should be from most specific to 438least specific in object order_. 439 440Other conditions such as `"browser"`, `"electron"`, `"deno"`, `"react-native"`, 441etc., are unknown to Node.js, and thus ignored. Runtimes or tools other than 442Node.js can use them at their discretion. Further restrictions, definitions, or 443guidance on condition names might occur in the future. 444 445Using the `"import"` and `"require"` conditions can lead to some hazards, 446which are further explained in [the dual CommonJS/ES module packages section][]. 447 448Conditional exports can also be extended to exports subpaths, for example: 449 450```json 451{ 452 "main": "./main.js", 453 "exports": { 454 ".": "./main.js", 455 "./feature": { 456 "node": "./feature-node.js", 457 "default": "./feature.js" 458 } 459 } 460} 461``` 462 463Defines a package where `require('pkg/feature')` and `import 'pkg/feature'` 464could provide different implementations between Node.js and other JS 465environments. 466 467When using environment branches, always include a `"default"` condition where 468possible. Providing a `"default"` condition ensures that any unknown JS 469environments are able to use this universal implementation, which helps avoid 470these JS environments from having to pretend to be existing environments in 471order to support packages with conditional exports. For this reason, using 472`"node"` and `"default"` condition branches is usually preferable to using 473`"node"` and `"browser"` condition branches. 474 475### Nested conditions 476 477> Stability: 1 - Experimental 478 479In addition to direct mappings, Node.js also supports nested condition objects. 480 481For example, to define a package that only has dual mode entry points for 482use in Node.js but not the browser: 483 484```json 485{ 486 "main": "./main.js", 487 "exports": { 488 "node": { 489 "import": "./feature-node.mjs", 490 "require": "./feature-node.cjs" 491 }, 492 "default": "./feature.mjs", 493 } 494} 495``` 496 497Conditions continue to be matched in order as with flat conditions. If 498a nested conditional does not have any mapping it will continue checking 499the remaining conditions of the parent condition. In this way nested 500conditions behave analogously to nested JavaScript `if` statements. 501 502### Resolving user conditions 503 504When running Node.js, custom user conditions can be added with the 505`--conditions` flag: 506 507```bash 508node --conditions=development main.js 509``` 510 511which would then resolve the `"development"` condition in package imports and 512exports, while resolving the existing `"node"`, `"default"`, `"import"`, and 513`"require"` conditions as appropriate. 514 515Any number of custom conditions can be set with repeat flags. 516 517### Self-referencing a package using its name 518 519Within a package, the values defined in the package’s 520`package.json` [`"exports"`][] field can be referenced via the package’s name. 521For example, assuming the `package.json` is: 522 523```json 524// package.json 525{ 526 "name": "a-package", 527 "exports": { 528 ".": "./main.mjs", 529 "./foo": "./foo.js" 530 } 531} 532``` 533 534Then any module _in that package_ can reference an export in the package itself: 535 536```js 537// ./a-module.mjs 538import { something } from 'a-package'; // Imports "something" from ./main.mjs. 539``` 540 541Self-referencing is available only if `package.json` has [`"exports"`][], and 542will allow importing only what that [`"exports"`][] (in the `package.json`) 543allows. So the code below, given the previous package, will generate a runtime 544error: 545 546```js 547// ./another-module.mjs 548 549// Imports "another" from ./m.mjs. Fails because 550// the "package.json" "exports" field 551// does not provide an export named "./m.mjs". 552import { another } from 'a-package/m.mjs'; 553``` 554 555Self-referencing is also available when using `require`, both in an ES module, 556and in a CommonJS one. For example, this code will also work: 557 558```js 559// ./a-module.js 560const { something } = require('a-package/foo'); // Loads from ./foo.js. 561``` 562 563## Dual CommonJS/ES module packages 564 565Prior to the introduction of support for ES modules in Node.js, it was a common 566pattern for package authors to include both CommonJS and ES module JavaScript 567sources in their package, with `package.json` [`"main"`][] specifying the 568CommonJS entry point and `package.json` `"module"` specifying the ES module 569entry point. 570This enabled Node.js to run the CommonJS entry point while build tools such as 571bundlers used the ES module entry point, since Node.js ignored (and still 572ignores) the top-level `"module"` field. 573 574Node.js can now run ES module entry points, and a package can contain both 575CommonJS and ES module entry points (either via separate specifiers such as 576`'pkg'` and `'pkg/es-module'`, or both at the same specifier via [Conditional 577exports][]). Unlike in the scenario where `"module"` is only used by bundlers, 578or ES module files are transpiled into CommonJS on the fly before evaluation by 579Node.js, the files referenced by the ES module entry point are evaluated as ES 580modules. 581 582### Dual package hazard 583 584When an application is using a package that provides both CommonJS and ES module 585sources, there is a risk of certain bugs if both versions of the package get 586loaded. This potential comes from the fact that the `pkgInstance` created by 587`const pkgInstance = require('pkg')` is not the same as the `pkgInstance` 588created by `import pkgInstance from 'pkg'` (or an alternative main path like 589`'pkg/module'`). This is the “dual package hazard,” where two versions of the 590same package can be loaded within the same runtime environment. While it is 591unlikely that an application or package would intentionally load both versions 592directly, it is common for an application to load one version while a dependency 593of the application loads the other version. This hazard can happen because 594Node.js supports intermixing CommonJS and ES modules, and can lead to unexpected 595behavior. 596 597If the package main export is a constructor, an `instanceof` comparison of 598instances created by the two versions returns `false`, and if the export is an 599object, properties added to one (like `pkgInstance.foo = 3`) are not present on 600the other. This differs from how `import` and `require` statements work in 601all-CommonJS or all-ES module environments, respectively, and therefore is 602surprising to users. It also differs from the behavior users are familiar with 603when using transpilation via tools like [Babel][] or [`esm`][]. 604 605### Writing dual packages while avoiding or minimizing hazards 606 607First, the hazard described in the previous section occurs when a package 608contains both CommonJS and ES module sources and both sources are provided for 609use in Node.js, either via separate main entry points or exported paths. A 610package might instead be written where any version of Node.js receives only 611CommonJS sources, and any separate ES module sources the package might contain 612are intended only for other environments such as browsers. Such a package 613would be usable by any version of Node.js, since `import` can refer to CommonJS 614files; but it would not provide any of the advantages of using ES module syntax. 615 616A package might also switch from CommonJS to ES module syntax in a [breaking 617change](https://semver.org/) version bump. This has the disadvantage that the 618newest version of the package would only be usable in ES module-supporting 619versions of Node.js. 620 621Every pattern has tradeoffs, but there are two broad approaches that satisfy the 622following conditions: 623 6241. The package is usable via both `require` and `import`. 6251. The package is usable in both current Node.js and older versions of Node.js 626 that lack support for ES modules. 6271. The package main entry point, e.g. `'pkg'` can be used by both `require` to 628 resolve to a CommonJS file and by `import` to resolve to an ES module file. 629 (And likewise for exported paths, e.g. `'pkg/feature'`.) 6301. The package provides named exports, e.g. `import { name } from 'pkg'` rather 631 than `import pkg from 'pkg'; pkg.name`. 6321. The package is potentially usable in other ES module environments such as 633 browsers. 6341. The hazards described in the previous section are avoided or minimized. 635 636#### Approach #1: Use an ES module wrapper 637 638Write the package in CommonJS or transpile ES module sources into CommonJS, and 639create an ES module wrapper file that defines the named exports. Using 640[Conditional exports][], the ES module wrapper is used for `import` and the 641CommonJS entry point for `require`. 642 643```json 644// ./node_modules/pkg/package.json 645{ 646 "type": "module", 647 "main": "./index.cjs", 648 "exports": { 649 "import": "./wrapper.mjs", 650 "require": "./index.cjs" 651 } 652} 653``` 654 655The preceding example uses explicit extensions `.mjs` and `.cjs`. 656If your files use the `.js` extension, `"type": "module"` will cause such files 657to be treated as ES modules, just as `"type": "commonjs"` would cause them 658to be treated as CommonJS. 659See [Enabling](#esm_enabling). 660 661```js 662// ./node_modules/pkg/index.cjs 663exports.name = 'value'; 664``` 665 666```js 667// ./node_modules/pkg/wrapper.mjs 668import cjsModule from './index.cjs'; 669export const name = cjsModule.name; 670``` 671 672In this example, the `name` from `import { name } from 'pkg'` is the same 673singleton as the `name` from `const { name } = require('pkg')`. Therefore `===` 674returns `true` when comparing the two `name`s and the divergent specifier hazard 675is avoided. 676 677If the module is not simply a list of named exports, but rather contains a 678unique function or object export like `module.exports = function () { ... }`, 679or if support in the wrapper for the `import pkg from 'pkg'` pattern is desired, 680then the wrapper would instead be written to export the default optionally 681along with any named exports as well: 682 683```js 684import cjsModule from './index.cjs'; 685export const name = cjsModule.name; 686export default cjsModule; 687``` 688 689This approach is appropriate for any of the following use cases: 690* The package is currently written in CommonJS and the author would prefer not 691 to refactor it into ES module syntax, but wishes to provide named exports for 692 ES module consumers. 693* The package has other packages that depend on it, and the end user might 694 install both this package and those other packages. For example a `utilities` 695 package is used directly in an application, and a `utilities-plus` package 696 adds a few more functions to `utilities`. Because the wrapper exports 697 underlying CommonJS files, it doesn’t matter if `utilities-plus` is written in 698 CommonJS or ES module syntax; it will work either way. 699* The package stores internal state, and the package author would prefer not to 700 refactor the package to isolate its state management. See the next section. 701 702A variant of this approach not requiring conditional exports for consumers could 703be to add an export, e.g. `"./module"`, to point to an all-ES module-syntax 704version of the package. This could be used via `import 'pkg/module'` by users 705who are certain that the CommonJS version will not be loaded anywhere in the 706application, such as by dependencies; or if the CommonJS version can be loaded 707but doesn’t affect the ES module version (for example, because the package is 708stateless): 709 710```json 711// ./node_modules/pkg/package.json 712{ 713 "type": "module", 714 "main": "./index.cjs", 715 "exports": { 716 ".": "./index.cjs", 717 "./module": "./wrapper.mjs" 718 } 719} 720``` 721 722#### Approach #2: Isolate state 723 724A [`package.json`][] file can define the separate CommonJS and ES module entry 725points directly: 726 727```json 728// ./node_modules/pkg/package.json 729{ 730 "type": "module", 731 "main": "./index.cjs", 732 "exports": { 733 "import": "./index.mjs", 734 "require": "./index.cjs" 735 } 736} 737``` 738 739This can be done if both the CommonJS and ES module versions of the package are 740equivalent, for example because one is the transpiled output of the other; and 741the package’s management of state is carefully isolated (or the package is 742stateless). 743 744The reason that state is an issue is because both the CommonJS and ES module 745versions of the package might get used within an application; for example, the 746user’s application code could `import` the ES module version while a dependency 747`require`s the CommonJS version. If that were to occur, two copies of the 748package would be loaded in memory and therefore two separate states would be 749present. This would likely cause hard-to-troubleshoot bugs. 750 751Aside from writing a stateless package (if JavaScript’s `Math` were a package, 752for example, it would be stateless as all of its methods are static), there are 753some ways to isolate state so that it’s shared between the potentially loaded 754CommonJS and ES module instances of the package: 755 7561. If possible, contain all state within an instantiated object. JavaScript’s 757 `Date`, for example, needs to be instantiated to contain state; if it were a 758 package, it would be used like this: 759 760 ```js 761 import Date from 'date'; 762 const someDate = new Date(); 763 // someDate contains state; Date does not 764 ``` 765 766 The `new` keyword isn’t required; a package’s function can return a new 767 object, or modify a passed-in object, to keep the state external to the 768 package. 769 7701. Isolate the state in one or more CommonJS files that are shared between the 771 CommonJS and ES module versions of the package. For example, if the CommonJS 772 and ES module entry points are `index.cjs` and `index.mjs`, respectively: 773 774 ```js 775 // ./node_modules/pkg/index.cjs 776 const state = require('./state.cjs'); 777 module.exports.state = state; 778 ``` 779 780 ```js 781 // ./node_modules/pkg/index.mjs 782 import state from './state.cjs'; 783 export { 784 state 785 }; 786 ``` 787 788 Even if `pkg` is used via both `require` and `import` in an application (for 789 example, via `import` in application code and via `require` by a dependency) 790 each reference of `pkg` will contain the same state; and modifying that 791 state from either module system will apply to both. 792 793Any plugins that attach to the package’s singleton would need to separately 794attach to both the CommonJS and ES module singletons. 795 796This approach is appropriate for any of the following use cases: 797* The package is currently written in ES module syntax and the package author 798 wants that version to be used wherever such syntax is supported. 799* The package is stateless or its state can be isolated without too much 800 difficulty. 801* The package is unlikely to have other public packages that depend on it, or if 802 it does, the package is stateless or has state that need not be shared between 803 dependencies or with the overall application. 804 805Even with isolated state, there is still the cost of possible extra code 806execution between the CommonJS and ES module versions of a package. 807 808As with the previous approach, a variant of this approach not requiring 809conditional exports for consumers could be to add an export, e.g. 810`"./module"`, to point to an all-ES module-syntax version of the package: 811 812```json 813// ./node_modules/pkg/package.json 814{ 815 "type": "module", 816 "main": "./index.cjs", 817 "exports": { 818 ".": "./index.cjs", 819 "./module": "./index.mjs" 820 } 821} 822``` 823 824## Node.js `package.json` field definitions 825 826This section describes the fields used by the Node.js runtime. Other tools (such 827as [npm](https://docs.npmjs.com/creating-a-package-json-file)) use 828additional fields which are ignored by Node.js and not documented here. 829 830The following fields in `package.json` files are used in Node.js: 831 832* [`"name"`][] - Relevant when using named imports within a package. Also used 833 by package managers as the name of the package. 834* [`"type"`][] - The package type determining whether to load `.js` files as 835 CommonJS or ES modules. 836* [`"exports"`][] - Package exports and conditional exports. When present, 837 limits which submodules can be loaded from within the package. 838* [`"main"`][] - The default module when loading the package, if exports is not 839 specified, and in versions of Node.js prior to the introduction of exports. 840* [`"imports"`][] - Package imports, for use by modules within the package 841 itself. 842 843### `"name"` 844<!-- YAML 845added: 846 - v12.16.0 847changes: 848 - version: 849 - v12.16.0 850 pr-url: https://github.com/nodejs/node/pull/31002 851 description: Remove the `--experimental-resolve-self` option. 852--> 853 854* Type: {string} 855 856```json 857{ 858 "name": "package-name" 859} 860``` 861 862The `"name"` field defines your package’s name. Publishing to the 863_npm_ registry requires a name that satisfies 864[certain requirements](https://docs.npmjs.com/files/package.json#name). 865 866The `"name"` field can be used in addition to the [`"exports"`][] field to 867[self-reference][] a package using its name. 868 869### `"type"` 870<!-- YAML 871added: v12.0.0 872changes: 873 - version: 874 - v12.17.0 875 pr-url: https://github.com/nodejs/node/pull/29866 876 description: Unflag `--experimental-modules`. 877--> 878 879* Type: {string} 880 881The `"type"` field defines the module format that Node.js uses for all 882`.js` files that have that `package.json` file as their nearest parent. 883 884Files ending with `.js` are loaded as ES modules when the nearest parent 885`package.json` file contains a top-level field `"type"` with a value of 886`"module"`. 887 888The nearest parent `package.json` is defined as the first `package.json` found 889when searching in the current folder, that folder’s parent, and so on up 890until a node_modules folder or the volume root is reached. 891 892```json 893// package.json 894{ 895 "type": "module" 896} 897``` 898 899```bash 900# In same folder as preceding package.json 901node my-app.js # Runs as ES module 902``` 903 904If the nearest parent `package.json` lacks a `"type"` field, or contains 905`"type": "commonjs"`, `.js` files are treated as [CommonJS][]. If the volume 906root is reached and no `package.json` is found, `.js` files are treated as 907[CommonJS][]. 908 909`import` statements of `.js` files are treated as ES modules if the nearest 910parent `package.json` contains `"type": "module"`. 911 912```js 913// my-app.js, part of the same example as above 914import './startup.js'; // Loaded as ES module because of package.json 915``` 916 917Regardless of the value of the `"type"` field, `.mjs` files are always treated 918as ES modules and `.cjs` files are always treated as CommonJS. 919 920### `"exports"` 921<!-- YAML 922added: v12.7.0 923changes: 924 - version: 925 - v12.16.0 926 pr-url: https://github.com/nodejs/node/pull/29978 927 description: Implement conditional exports. 928 - version: 929 - v12.16.0 930 pr-url: https://github.com/nodejs/node/pull/31001 931 description: Remove the `--experimental-conditional-exports` option. 932 - version: 933 - v12.16.0 934 pr-url: https://github.com/nodejs/node/pull/31008 935 description: Implement logical conditional exports ordering. 936 - version: 937 - v12.20.0 938 pr-url: https://github.com/nodejs/node/pull/34718 939 description: Add support for `"exports"` patterns. 940--> 941 942* Type: {Object} | {string} | {string[]} 943 944```json 945{ 946 "exports": "./index.js" 947} 948``` 949 950The `"exports"` field allows defining the [entry points][] of a package when 951imported by name loaded either via a `node_modules` lookup or a 952[self-reference][] to its own name. It is supported in Node.js 12+ as an 953alternative to the [`"main"`][] that can support defining [subpath exports][] 954and [conditional exports][] while encapsulating internal unexported modules. 955 956[Conditional Exports][] can also be used within `"exports"` to define different 957package entry points per environment, including whether the package is 958referenced via `require` or via `import`. 959 960All paths defined in the `"exports"` must be relative file URLs starting with 961`./`. 962 963### `"main"` 964<!-- YAML 965added: v0.4.0 966--> 967 968* Type: {string} 969 970```json 971{ 972 "main": "./main.js" 973} 974``` 975 976The `"main"` field defines the script that is used when the [package directory 977is loaded via `require()`](modules.html#modules_folders_as_modules). Its value 978is interpreted as a path. 979 980```js 981require('./path/to/directory'); // This resolves to ./path/to/directory/main.js. 982``` 983 984When a package has an [`"exports"`][] field, this will take precedence over the 985`"main"` field when importing the package by name. 986 987### `"imports"` 988<!-- YAML 989added: v12.19.0 990--> 991 992> Stability: 1 - Experimental 993 994* Type: {Object} 995 996```json 997// package.json 998{ 999 "imports": { 1000 "#dep": { 1001 "node": "dep-node-native", 1002 "default": "./dep-polyfill.js" 1003 } 1004 }, 1005 "dependencies": { 1006 "dep-node-native": "^1.0.0" 1007 } 1008} 1009``` 1010 1011Entries in the imports field must be strings starting with `#`. 1012 1013Import maps permit mapping to external packages. 1014 1015This field defines [subpath imports][] for the current package. 1016 1017[Babel]: https://babeljs.io/ 1018[Conditional exports]: #packages_conditional_exports 1019[CommonJS]: modules.html 1020[`ERR_PACKAGE_PATH_NOT_EXPORTED`]: errors.html#errors_err_package_path_not_exported 1021[ES modules]: esm.html 1022[ES module]: esm.html 1023[`esm`]: https://github.com/standard-things/esm#readme 1024[`"exports"`]: #packages_exports 1025[`"main"`]: #packages_main 1026[`"name"`]: #packages_name 1027[`"imports"`]: #packages_imports 1028[`"type"`]: #packages_type 1029[entry points]: #packages_package_entry_points 1030[`package.json`]: #packages_node_js_package_json_field_definitions 1031[self-reference]: #packages_self_referencing_a_package_using_its_name 1032[subpath exports]: #packages_subpath_exports 1033[subpath imports]: #packages_subpath_imports 1034[the full specifier path]: esm.md#esm_mandatory_file_extensions 1035[the dual CommonJS/ES module packages section]: #packages_dual_commonjs_es_module_packages 1036