modules-packagingAnswer last reviewed July 2026

Tell me about the exports field in package.json. What does it actually change, and what's this dual-package hazard people talk about?

Strong candidates treat the exports map as a public API contract enforced at resolve time, and can spot the dual-package hazard from its symptoms alone

What an AI-prepared candidate might say

So exports is how a package defines its public entry points. Before that you had main, which named one default file and left every other path in the package open. exports replaces that with a map, . covers the root, subpaths like ./utils cover the rest, and conditions like import, require, node, and default pick different files depending on the consumer. Usually that means importers get an ESM build and requirers get a CJS build. And anything not listed in the map just can't be imported at all, which is how a package hides its internals. The dual-package hazard is, I think, the cost of shipping both formats. The same package can load twice in one process, once as CJS and once as ESM, and the two copies don't share state, so singletons break and instanceof checks fail. There's also an imports field that does the same mapping for a package's own internal aliases, with # prefixes.

Senior
Locked

How conditions match in key order, subpath patterns, the imports (#) map, and the exact mechanics that let one package quietly become two instances.

Unlock the depth
Staff
Locked

How to prove a double-load in a live process, the publishing choices that dodge the hazard, and why exports changes turned into a breaking-change vector semver never sees.

Unlock the depth
Follow-up chain
Tell me about the exports field in package.json. What does it actually change, and what's this dual-package hazard people talk about? | NodeBook