Frontend engineer path · The language · Topic 6 of 17

Modules (ESM vs CommonJS)

Not started

ES modules use import and export, which are read before any code runs, so imports are hoisted, bindings stay live, and top-level await is allowed. CommonJS uses require(), which loads and runs a file synchronously and hands back its module.exports object. Node supports both, chosen by .mjs/.cjs or the "type" field in package.json, and from Node 22.12 require() can also load an ES module that has no top-level await.

Why it matters: Mixing the two is behind most "cannot use import statement outside a module" and default-export puzzles.

1

How it works

The explanation, with examples you can run.

Side by side

ES modulesCommonJS
Syntaximport / exportrequire() / module.exports
When it is resolvedBefore any code runs (static)When the require line runs
LoadingCan be asynchronous; allows top-level awaitSynchronous
ExportsLive bindings: importers see later changesA plain object, copied out at require time if you destructure
Strict modeAlwaysOnly with "use strict"
File locationimport.meta.url, import.meta.dirname__filename, __dirname

Mixing them in Node

  • An ES module can import a CommonJS file. Its module.exports becomes the default export, and Node tries to detect named exports too.
  • A CommonJS file can load an ES module with await import(), and since Node 22.12 also with plain require(), as long as that module (and its imports) use no top-level await.
  • In ES modules, relative imports need the full file name: import "./util.js", not "./util".
// math.mjsexport let calls = 0export function add(a, b) {  calls++  return a + b} // main.mjs (run with: node main.mjs)import { add, calls } from "./math.mjs"add(1, 2)console.log(calls) // 1: the binding is live, not a copy
2

Check yourself

2 questions. Get them all right to finish this topic.

  1. 1.In Node 22, which file is always treated as an ES module, whatever package.json says?
  2. 2.What does a CommonJS file get back from require("./other.js")?

0 of 2 right so far. Get all two to finish this topic.