If you just added "type": "module" to package.json and your test runner died with ERR_REQUIRE_ESM, this article gets you back to green in about 15 minutes. By the end you'll have a copy-pasteable decision map for .js / .cjs / .mjs, a working dual-format build, and the three config files (Jest, ESLint, a small CLI) that break most often — with the exact error strings so you can Ctrl+F your stack trace.
I migrated a 42-file internal tooling repo last month. The flag flip took 4 seconds; the fallout took 3 hours. Here's the part nobody writes down.
The one rule that explains every ERR_REQUIRE_ESM and ERR_MODULE_NOT_FOUND
Result first: in Node 20–24, the "type" field in the nearest package.json decides how .js files are parsed. "type": "module" → every .js is ESM. No field, or "type": "commonjs" → every .js is CJS. The extensions .cjs and .mjs ignore the field entirely and are always CJS and ESM respectively.
So 90% of migration pain is one of two mismatches:






