100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace

JavaScript Modules (ESM/CJS) Cheat Sheet

JavaScript Modules (ESM/CJS) Cheat Sheet

Covers ES module import/export syntax, CommonJS require/module.exports, Node.js module configuration, and interoperability between the two systems.

1 PageIntermediateApr 12, 2026

ES Modules (ESM)

The standard, static module system.

javascript
// math.jsexport const PI = 3.14159;export function add(a, b) { return a + b; }export default function multiply(a, b) { return a * b; }// app.jsimport multiply, { PI, add } from "./math.js";   // Default + named importsimport * as math from "./math.js";                // Namespace importexport { add as sum };                             // Re-export with renameexport * from "./math.js";                          // Re-export everything// Note: ESM import paths require file extensions in Node.js (./math.js, not ./math)

CommonJS (CJS)

Node's original, synchronous module system.

javascript
// math.jsconst PI = 3.14159;function add(a, b) { return a + b; }module.exports = { PI, add };// or: module.exports.add = add;// or a single default-like export: module.exports = add;// app.jsconst { PI, add } = require("./math.js");const math = require("./math.js");    // Whole module object// require() is synchronous and can be called conditionally/anywhere in the fileif (process.env.DEBUG) {  const debug = require("./debug.js");}

Configuring Module Type in Node.js

package.json's "type" field decides how .js files are parsed.

json
// package.json{  "name": "my-app",  "type": "module",  "main": "index.js"}// "type": "module"    -> .js files are treated as ESM// "type": "commonjs"  (default) -> .js files are treated as CJS// Use .mjs to force ESM and .cjs to force CJS regardless of "type"

Interop Between ESM and CJS

Mixing the two systems has a few hard rules.

javascript
// Importing a CJS module from ESM: works, module.exports becomes the default exportimport pkg from "./legacy-cjs-module.js";const { someFn } = pkg;// Dynamic import works in both ESM and CJS, always returns a Promiseasync function load() {  const mod = await import("./math.js");  mod.add(1, 2);}// require()-ing an ESM file from CJS throws --// ESM cannot be require()'d directly, use dynamic import() instead

Key Differences

What actually changes between the two systems.

  • Loading- CJS require() is synchronous; ESM import is asynchronous under the hood
  • Hoisting- ESM imports are hoisted and resolved before any code runs; CJS require() executes inline
  • this at top level- undefined in ESM modules; module.exports in CJS modules
  • __dirname / __filename- Available in CJS; in ESM, derive them via import.meta.url instead
  • Tree-shaking- ESM's static import/export structure lets bundlers eliminate unused exports; CJS's dynamic nature mostly prevents it
  • Live bindings- ESM named exports are live references to the source; CJS exports are copied values at require time
Pro Tip

Don't mix require() and import in the same file expecting them to behave identically -- if package.json has "type": "module", every .js file is parsed as ESM and require is undefined by default; use createRequire from 'module' if you truly need CJS require inside an ESM file.

Was this cheat sheet helpful?

Explore Topics

#JavaScriptModulesESMCJS#JavaScriptModulesESMCJSCheatSheet#Programming#Intermediate#ESModulesESM#CommonJSCJS#Configuring#Module#CheatSheet#SkillVeris
Advertisement
Sri Hayavadhana Info-Tech

Professional Web Designing Services

  • Responsive Websites
  • E-commerce Solutions
  • SEO Friendly Design
  • Fast & Secure
  • Support & Maintenance
Get a Free Quote

Share this Cheat Sheet