The "exports" Field & ESM vs CJS

Master package entry points, conditional resolution for ES Modules and CommonJS, and subpath encapsulation using package.json exports.

Package Managers4 min readConcept 3 of 24

What is the exports field?

The exports field in package.json defines explicit subpath mappings and condition-based entry points for a package, taking precedence over legacy main. It provides package encapsulation by blocking access to internal private files.

Why is exports critical for modern packages?

Modern Node.js applications use dual module systems (ES Modules via import and CommonJS via require()). The exports field allows a single package to serve optimized ESM builds (.mjs), CJS fallbacks (.cjs), and clean subpath shortcuts (my-pkg/utils) while preventing consumers from importing un-exported internal source files (my-pkg/src/internal.js).

How to configure conditional exports

Declare exports in package.json. Use condition keys like import, require, node, and default. Map root import . to { "import": "./dist/index.mjs", "require": "./dist/index.cjs" } and subpaths like ./utils to ./dist/utils.js.

Simulate Module Resolution

Select an import statement or resolution condition below to trace how Node.js matches package.json exports and resolves target files on disk.

Module Resolver Scenarios:
package.json Manifestexports precedence active
1{
2 "name": "my-pkg",
3 "version": "1.0.0",
4 "main": "./dist/index.cjs",
5 "exports": {
6 ".": {
7 "types": "./dist/index.d.ts",
8 "import": "./dist/index.mjs",
9 "require": "./dist/index.cjs"
10 },
11 "./utils": {
12 "types": "./dist/utils/index.d.ts",
13 "default": "./dist/utils/index.js"
14 }
15 }
16}

Module Resolution Pipeline

Node.js export map resolution simulator

RESOLVED
Consumer Import Expression:
import { helper } from "my-pkg";
Matched Condition Key:

"import" condition on root "." export

Target File on Disk:
./dist/index.mjs
Package Encapsulation Status:

Node.js evaluates the ES Module import statement, matches condition key "import", and resolves to the ESM bundle at ./dist/index.mjs.

Legacy Fallback: "main": "./dist/index.cjs"Node.js v12.7+

Module Resolver active scenario: ESM import

Remember this

  • The exports field takes precedence over main in modern Node.js runtimes.
  • Conditional exports map import for ES Modules and require for CommonJS.
  • Subpath exports provide package encapsulation, preventing consumers from importing internal private files.
  • Always list default as the final condition key and use fallback main for legacy bundler compatibility.

Done with this concept?

Mark it complete to track your progress. No login needed.