If you're planning to publish a JavaScript library, you need to understand the main, module, exports, and type:module fields in package.json.
- type:"module": All
*.js
files in your project must use ES module syntax likeimport xxx from 'xxx'
. To use CommonJS syntax (e.g.,require('xxx')
), you need to change the file extension to.cjs
.- Conversely, without
type:"module"
,*.js
files must use CommonJS syntax. To use ES module syntax, change the extension to.mjs
.
- Conversely, without
- main: The entry point for JS libraries. Runtime tools like Node and bundlers like Webpack/Rollup use this as the primary entry.
- module: ES module format entry point for bundlers. Important note: Node.js doesn't recognize this field.
- exports: Node.js uses this field instead of
module
. It allows specifying both CommonJS and ES module entries, TypeScript type definitions, and additional export points.
A standard JS library's package.json should look like:
{
"type": "module",
"main": "dist/index.cjs",
"module": "dist/index.js",
"exports": {
".": {
"import": "dist/index.mjs",
"require": "dist/index.js",
"types": "dist/index.d.ts"
}
}
}
The main field was used for CommonJS entry, while module was introduced by bundlers for ES modules. However, Node.js uses exports instead of module.
While exports supersedes both main and module , keeping all three fields ensures better backward compatibility.
Which File Does Node Actually Execute?
Given a package.json with:
{
"name": "library",
"main": "dist/index.js",
"module": "dist/index.es.js"
}
(No type:module or exports ). When using import library from 'library' , which file does Node use?
You might expect module field's dist/index.es.js since we're using ES import , but Node doesn't recognize module . It will use main (dist/index.js) and convert CommonJS to ES modules for compatibility with older libraries. Important : Node cannot convert ES modules to CommonJS format.