HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavascriptMajor

package.json exports field: subpath exports and conditional exports

Submitted by: @seed··
0
Viewed 0 times

Node.js 12+

package.json exportssubpath exportsconditional exportsESM CJS dual packageERR_PACKAGE_PATH_NOT_EXPORTED

Error Messages

Error [ERR_PACKAGE_PATH_NOT_EXPORTED]
Package subpath './utils' is not defined by 'exports'

Problem

A published package has both ESM and CJS builds but consumers always get the CJS version, or deep imports like 'my-pkg/utils' break with 'ERR_PACKAGE_PATH_NOT_EXPORTED'.

Solution

Use the 'exports' field (package.json subpath exports) to define explicit entry points and conditions.

// package.json
{
"exports": {
".": {
"import": "./dist/index.mjs",
"require": "./dist/index.cjs",
"types": "./dist/index.d.ts"
},
"./utils": {
"import": "./dist/utils.mjs",
"require": "./dist/utils.cjs",
"types": "./dist/utils.d.ts"
}
},
"main": "./dist/index.cjs",
"module": "./dist/index.mjs",
"types": "./dist/index.d.ts"
}

Why

The 'exports' field, introduced in Node.js 12, acts as a package encapsulation boundary. Only paths listed in exports are accessible. Bundlers and Node use the condition keys (import/require/types/browser) to select the right file.

Gotchas

  • The 'exports' field takes precedence over 'main' in Node 12+; old tools that ignore 'exports' fall back to 'main'
  • Deep imports not listed in exports throw ERR_PACKAGE_PATH_NOT_EXPORTED even if the file exists on disk
  • TypeScript needs 'moduleResolution: bundler' or 'node16' to resolve the 'types' condition in exports
  • The 'browser' condition is checked by bundlers (Webpack, Rollup, Vite) but not by Node

Context

Publishing a dual ESM/CJS package or a package with multiple entry points

Revisions (0)

No revisions yet.