AceDevHub
Intermediate Node.js Interview QuestionsIntermediateConcept

Node.js · Question 34

What is the difference between CommonJS and ES modules in Node.js?

Direct answer

CommonJS uses require/module.exports with synchronous load and runtime resolution; ES modules use import/export with static analysis, async top-level await, and live bindings — Node supports both; package.json "type" and .mjs/.cjs extensions pick the default.

Node evolved from CommonJS (CJS) as its original module system to native ECMAScript modules (ESM) aligned with browser JavaScript. AceDevHub's monorepo uses ESM in apps/api and apps/web with "type": "module" or .mjs where needed.

Why interviewers ask

AspectCommonJSES Modules
Syntaxrequire(), module.exportsimport / export
LoadingSynchronous at require timeAsync graph; import hoisted
AnalysisDynamic — require(variable)Static — imports must be top-level strings
Default in Node.js when "type": "commonjs" or absent.js when "type": "module"
InteropcreateRequire, dynamic import()import() for CJS default export
  • When to use ESM — new Node projects, shared isomorphic code with browsers, top-level await in scripts.
  • When CJS remains — legacy packages, some tooling configs, gradual migration paths.
cjs-vs-esm
// CommonJS (utils.cjs)
const path = require("node:path");
module.exports = { join: path.join };

// ES Module (utils.mjs)
import path from "node:path";
export const join = path.join;

// ESM importing CJS
import pkg from "legacy-cjs-package";
const { createRequire } = await import("node:module");
const require = createRequire(import.meta.url);