Repository navigation
Recommend node/default conditions instead of require/import as a solution to the dual package hazard #52174
Description
Activity
- addeddocIssues and PRs related to Node.js documentation.Issues and PRs related to Node.js documentation.
on Mar 21, 2024 - addedgood first issueIssues that are suitable for first-time contributors.Issues that are suitable for first-time contributors.
on Apr 11, 2024 Looks like a good first issue. Relevant file is https://github.com/nodejs/node/blob/main/doc/api/packages.md
@joyeecheung , @nicolo-ribaudo this issue is still relevant ?
Yes, IMO the doc can still be improved as suggested in the OP.
Reacted by Eliphaz BouyeIs there still work to be done here?
In #54648 which adds a new pattern I realize that it just doesn't seem appropriate to document them this way in the API docs. To quote my comments:
- It teaches opinionated practices that some consider dangerous
- It will soon be obsolete when we unflag --experimental-require-module.
- It's difficult to understand a multi-file structure via long texts and snippets in a (rendered) markdown document.
I think they should just be placed in their own example repo with some notes on pros/cons and maybe links to threads of discussions. But anyway API docs is the wrong place for them.
Reacted by StevenIt will soon be obsolete when we unflag --experimental-require-module.
May I ask if there is some schedule for unflagging this? Given the node 22 LTS is nearby, any chance it would happen with that version already?
"module-sync"must exist above"node"(or"require") if applicable.{ "name": "foo", "exports": { "module-sync": "./foo.mjs", "node": "./foo.cjs", "default": "./foo.mjs" } }Hi, I’d like to work on this issue as my first documentation contribution. Is it still available?
I'd like to work on this issue.
Hi, I’m a new contributor and would like to help with documentation improvements.
Is there still any work needed for this issue, or should new contributions target a different repository?can i go for it?
- added a commit that references this issue
on Apr 7, 2026 Should this issue still be open, given your comments in #52174 (comment) and creation of the https://github.com/nodejs/package-examples repo?
It's also labeled with good first issueIssues that are suitable for first-time contributors. .
Edit: label removed Jul 21, 2026
New contributors are still attempting to resolve it.- added a commit that references this issue
on Apr 14, 2026 github-actions commented
on Jul 20, 2026 on Jul 20, 2026 – with GitHub ActionsContributorMore actionsThis issue has been marked as stale due to 90 days of inactivity.
It will be automatically closed in 30 days if no further activity occurs. If this is still relevant, please leave a comment or update it to keep it open.- addedstaleIssues and PRs marked stale due to inactivity and scheduled for automatic closure.Issues and PRs marked stale due to inactivity and scheduled for automatic closure.
on Jul 20, 2026 Not stale
- removedstaleIssues and PRs marked stale due to inactivity and scheduled for automatic closure.Issues and PRs marked stale due to inactivity and scheduled for automatic closure.
on Jul 21, 2026 - removedgood first issueIssues that are suitable for first-time contributors.Issues that are suitable for first-time contributors.
on Jul 21, 2026
Affected URL(s)
https://nodejs.org/api/packages.html#dual-package-hazard
Description of the problem
Publishing packages with dual CommonJS and ESM sources, while has the benefits of supporting both CJS consumers and ESM-only platforms, is known to cause problems because Node.js might load both versions. Example:
package.jsonfoo.cjsfoo.mjs{ "name": "foo", "exports": { "require": "./foo.cjs", "import": "./foo.mjs" } }package.jsonbar.js{ "name": "bar", "main": "./bar.js" }The two suggested solutions boil down to "even when you have an ESM entrypoint, still use only CJS internallly". This solves the dual package hazard, but completely defeats the cross-platform benefits of dual modules.
If
fooinstead used these export conditions:{ "name": "foo", "exports": { "node": "./foo.cjs", "default": "./foo.mjs" } }Then:
nodeversion (if they are configured to target Node.js) or thedefaultversion (if they are configured to target other platforms).We have been using this
node/defaultpattern in@babel/runtimefor a couple years, because we wanted to provide an ESM-only version for browsers while still avoiding the dual-package hazard (@babel/runtimeis mostly stateless, but@babel/runtime/helpers/temporalUndefinedrelies on object identity of an object defined in a separate file).