Interview Q&A / Node.js

BeginnerIn-depth2 min readUpdated 2 Oct 2026

What is the difference between CommonJS (require) and ES modules (import) in Node.js?

SHORT ANSWER

CommonJS uses require and module.exports, loads files synchronously, and was Node's original system. ES modules use import and export, are the JavaScript standard, are analysed before running, and support top-level await. Node supports both.

Explain it simply

Both are ways to split code into files and share functions between them. Think of two ways of ordering food in a hostel. CommonJS is like walking to the mess and picking up your plate when you need it: require runs at that moment and hands you whatever the other file exported. ES modules are like a pre-booked thali: before anything runs, Node reads every import line, plans which files are needed, links them, and only then starts executing.

CommonJS came first because JavaScript had no module system when Node was created. ES modules (ESM) were added to the language later, in ES2015, and are what browsers use too. New projects usually choose ESM.

Example

CommonJS:

js
// math.cjs
function add(a, b) { return a + b; }
module.exports = { add };

// app.cjs
const { add } = require("./math.cjs");
console.log(add(2, 3)); // 5

ES modules:

js
// math.mjs
export function add(a, b) { return a + b; }

// app.mjs
import { add } from "./math.mjs";
console.log(add(2, 3)); // 5

How it works

Node decides which system a file uses:

  • .cjs is always CommonJS, .mjs is always ESM.
  • For .js, it checks the nearest package.json. "type": "module" means ESM; otherwise CommonJS.

Key differences:

CommonJSES modules
Syntaxrequire, module.exportsimport, export
LoadingSynchronous, at runtimeParsed and linked before running
Top-level awaitNoYes
__dirname, __filenameAvailableUse import.meta.dirname / import.meta.filename
File extension in relative pathsOptionalRequired (./math.js)
ExportsA copy of the value at the time of exportLive bindings

Real-world use

Older Express apps and many tutorials use CommonJS. Modern packages, Vite projects and newer Node services use ESM. Because ESM is static, bundlers can do tree shaking and remove unused exports, which keeps frontend bundles smaller.

Common mistakes

  • Forgetting the file extension in an ESM import (./utils instead of ./utils.js).
  • Using __dirname inside an ES module and getting a ReferenceError.
  • Mixing require and import in the same file without knowing which mode the file is in.
  • Expecting import statements to work conditionally inside an if. Use dynamic import() for that.

What to say in the interview

"CommonJS is Node's original module system, with require and module.exports. It loads modules synchronously when the line runs. ES modules are the official JavaScript standard, with import and export. They are statically analysed before execution, which enables tree shaking and top-level await, and their exports are live bindings. Node picks the system by file extension or the type field in package.json. For new code I use ES modules, and I use dynamic import() when I need to load something conditionally."

Follow-up questions

  • Can a CommonJS file load an ES module?
  • What does "type": "module" in package.json change?
  • What is tree shaking and why does it need ES modules?

Go deeper

Read these once the basics above feel easy.

An ES module can import a CommonJS module; the module.exports object becomes the default export. Going the other way used to require dynamic import(), which returns a promise. Recent Node versions also allow require() of an ES module as long as that module graph has no top-level await. If you publish a library, the exports field in package.json lets you ship separate entry points for import and require users.

#nodejs#modules#commonjs#esm

Related questions

Practise more Node.js questions

Test your recall with short answers, then return to the detailed explanations when you need context.

Open Node.js quick answers →

Get new questions like this by email

One short email when something new and useful lands. No spam, unsubscribe in one tap.

By subscribing you agree to the Privacy Policy.