mediumFull Stack EngineerTechnology
How do ES Modules differ from CommonJS in Node.js, and what are the migration challenges?
Posted 18/04/2026
by Mehedy Hasan Ador
Question Details
At a Node.js-heavy company:
> "We're migrating our codebase from CommonJS to ES Modules. Some packages only ship CJS, some only ESM. Our Jest tests broke after switching. What are the key differences and how do we handle interoperability?"
> "We're migrating our codebase from CommonJS to ES Modules. Some packages only ship CJS, some only ESM. Our Jest tests broke after switching. What are the key differences and how do we handle interoperability?"
Suggested Solution
Key Differences
require() / module.exportsimport / exportthis at topmodule.exportsundefinedInteroperability
// CJS importing ESM (dynamic import only)
const { default: esmModule } = await import("./esm-module.mjs");
// ESM importing CJS (named imports may not work)
import cjsModule from "./cjs-module.cjs"; // ✅ default import works
import { specific } from "./cjs-module.cjs"; // ⚠️ May fail
Migration Challenges
1._dirname and filename not available in ESM:// ESM replacement
import { fileURLToPath } from "url";
import { dirname } from "path";
const filename = fileURLToPath(import.meta.url);
const dirname = dirname(_filename);
2. JSON imports require assertion:import pkg from "./package.json" with { type: "json" };
3. Jest ESM support: Use --experimental-vm-modules or switch to Vitest4. Package.json:
"type": "module" makes all .js files ESM by defaultBest Practice for New Projects
// package.json
{ "type": "module" }
Use .mts/.mts extensions for explicit ESM, .cts` for CJS.