CodePark/ questions / Modules (CommonJS & ESM)
START PRACTICINGPRACTICE
Backend question · Node.js › Modules (CommonJS & ESM)

What does the exports field in package.json do, and how does it differ from main?

{
  "name": "my-lib",
  "exports": {
    ".": {
      "import": "./dist/index.mjs",
      "require": "./dist/index.cjs"
    },
    "./utils": "./dist/utils.js"
  }
}

main sets one entry point. exports sets the full public interface and blocks everything else.

main names the single entry point that Node uses when someone requires the package by name. Every other file stays reachable by deep paths like pkg/lib/internal.js.

exports lists the package's public interface explicitly. In modern Node it takes priority over main. Only the listed subpaths can be imported. Anything else throws ERR_PACKAGE_PATH_NOT_EXPORTED. This lets authors hide internal files and refactor safely.

exports also supports conditional exports. One package can point import at an ESM build and require at a CommonJS build. It can also use keys like types or default.

Adding exports to an existing package can break users who relied on deep imports. So it is treated as a breaking change.

  • main is one entry point, and deep paths stay reachable.
  • exports lists the allowed subpaths and blocks the rest.
  • Conditional exports give separate targets for import and require.
  • exports wins over main when both exist.
  • Adding exports to a package can be a breaking change.