Andrew's Digital Garden

Entry points in package.json

There's three different ways of dictating the entry point of your package in a package.json. These are mostly due to slow changes over time in Node.

main was the original, module was an unofficial standard, and exports is the new way.

main is supported in all versions of Node, but doesn't have much flexibility. It's recommended to still use it for backwards compatibility of other tools/plugins. exports allows multiple entry points to be defined, including different entry points depending on environments, such as CJS/ESM. exports takes priority over main, in supported versions.

Note that module is still used by Typescript is moduleResolution is set to node.

I've found the best usage to be something like the following, taken from clsx:

{ "main": "dist/clsx.js", // CJS, as most newer things use exports "module": "dist/clsx.mjs", // ESM "types": "clsx.d.ts", "exports": { ".": { // For ESM "import": { // types per exports field is best practice "types": "./clsx.d.mts", "default": "./dist/clsx.mjs" }, // For CJS, as a fallback // I've also seen `require` used as a key for CJS, then usually `default` is made ESM, but that should be unnecessary. "default": { "types": "./clsx.d.ts", "default": "./dist/clsx.js" } }, // Multiple entry points supported "./lite": { "import": { "types": "./clsx.d.mts", "default": "./dist/lite.mjs" }, "default": { "types": "./clsx.d.ts", "default": "./dist/lite.js" } } }

[[20250627100132-js-module-types]]

https://stackoverflow.com/questions/68572936/what-is-the-difference-between-main-and-module-vs-exports-in-package-json

[[buildtooling]] [[dependencies]] [[node]] [[npm]]

Entry points in package.json