JavaScript · The language round

What is the difference between ES modules and CommonJS?

MediummodulesesmcommonjsUpdated Oct 2026
Quiz this track

Short answer

ES modules use static import/export, live bindings and top-level await. CommonJS uses require and module.exports, loads synchronously, and is the older Node.js format.

The formats differ in syntax, loading behaviour and how bundlers can optimise them. Modern browser code and new Node.js code generally use ES modules.

js
// ES module
import { readFile } from "node:fs/promises";
export const name = "esm";

// CommonJS
const { readFile } = require("node:fs/promises");
module.exports = { name: "cjs" };

The important differences

  • ESM imports are static and hoisted; require can be called anywhere
  • ESM exports are live bindings; CommonJS exports are values copied at require time
  • ESM supports top-level await; CommonJS does not
  • ESM is strict mode by default; CommonJS is not
  • CommonJS caches modules by resolved path; ESM also caches module instances
  • Bundlers can tree-shake ESM more effectively because the graph is static

In Node.js, the type field in package.json decides whether .js files are treated as ESM or CommonJS. .mjs and .cjs override that default.

Dynamic import() works in both formats and returns a promise. It is the escape hatch when you need to load a module conditionally or at runtime.

Follow-ups you should expect

Interviewers use these to check whether the first answer was understanding or memorisation.

  1. 1What does it mean that ESM exports are live bindings?
  2. 2Can CommonJS use top-level await?
  3. 3How does dynamic `import()` differ from a static import?
  4. 4How does Node.js decide whether a file is ESM or CommonJS?

Say it in the interview

ES modules use import and export, are static, strict by default, and expose live bindings. CommonJS uses require and module.exports, loads synchronously, and copies values at require time. ESM supports top-level await and tree shaking because the dependency graph is known ahead of time. Dynamic import works in both and returns a promise.

Use this as a model, not a script. Saying it in your own words is what makes it survive follow-up pressure.

Related questions

Reading is step one

Now say it out loud.

Understanding an answer and delivering it under pressure are different skills. Rehearse this topic in a live JavaScript mock interview and get scored feedback on depth, clarity and confidence.