Skip to content
Laviyx Learn

Try

Node.js and Express course menu

Node.js Modules: ES Modules vs CommonJS (import and require)

Organise Node.js code into modules: ES modules with import and export, named and default exports, the node: prefix for built-in modules, CommonJS with require and module.exports, choosing between them with package.json type, and import.meta.dirname.

Beginner7 min readUpdated
On this page

Real programs are split into many files. Each file is a module with its own scope: variables in one file are invisible to others unless they are exported. Node.js supports two module systems: modern ES modules (ESM, import/export, the JavaScript standard) and the older CommonJS (require/module.exports), which you will still meet in many existing projects.

ES modules#

Tell Node to treat .js files as ES modules with "type": "module" in package.json:

package.json (JSON)
{
  "type": "module"
}

A module with named exports:

pricing.js (JavaScript)
export const GST_RATE = 0.18;

export function withGst(amount) {
  return Math.round(amount * (1 + GST_RATE) * 100) / 100;
}

export function formatRupees(amount) {
  return `₹${amount.toLocaleString("en-IN", { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`;
}

and one with a default export:

cart.js (JavaScript)
import { withGst } from "./pricing.js";

export default function cartTotal(items) {
  const subtotal = items.reduce((sum, item) => sum + item.price * item.qty, 0);
  return withGst(subtotal);
}

Using them:

app.js (JavaScript)
import cartTotal from "./cart.js";
import { GST_RATE, formatRupees } from "./pricing.js";

const items = [
  { name: "Notebook", price: 60, qty: 3 },
  { name: "Pen", price: 25, qty: 4 },
];
console.log(`GST rate: ${GST_RATE * 100}%`);
console.log("Total:", formatRupees(cartTotal(items)));
Terminal
node app.js
Output
GST rate: 18%
Total: ₹330.40

Rules worth remembering:

  • Relative imports need the file extension: "./pricing.js", not "./pricing".
  • A module can have many named exports but only one default export. Named imports use braces and the exact names (rename with as: import { withGst as addTax }); a default import can use any name.
  • Each module runs once, the first time it is imported; later imports share the same exported values.

Built-in modules and the node: prefix#

Node's own modules are imported the same way. The node: prefix makes clear it is a built-in, not a package from npm:

JavaScript
import { readFile } from "node:fs/promises";
import path from "node:path";
import os from "node:os";

console.log(path.extname("report.final.pdf"));
console.log(typeof readFile);
console.log(os.EOL === "\n" || os.EOL === "\r\n");
Output
.pdf
function
true

The file's own folder#

In ES modules, import.meta.dirname is the folder of the current file and import.meta.filename its full path, useful for reading files that sit next to your code regardless of where node was started:

where.js (JavaScript)
import path from "node:path";

const dataFile = path.join(import.meta.dirname, "data", "products.json");
console.log(path.basename(dataFile));
console.log(path.basename(import.meta.filename));
Terminal
node where.js
Output
products.json
where.js

CommonJS#

CommonJS uses require() to import and module.exports to export. It is the default when package.json has no "type" (or "type": "commonjs"), and for files ending in .cjs:

greet.cjs (JavaScript)
function greet(name) {
  return `Namaste, ${name}!`;
}

module.exports = { greet };
main.cjs (JavaScript)
const { greet } = require("./greet.cjs");
const path = require("node:path");

console.log(greet("Ravi"));
console.log(path.basename(__filename));
Terminal
node main.cjs
Output
Namaste, Ravi!
main.cjs

CommonJS has __dirname and __filename built in; ES modules use import.meta.dirname and import.meta.filename instead.

Which should you use?#

ES modulesCommonJS
Syntaximport / exportrequire / module.exports
Standardyes, also in browsersNode-specific
Top-level awaityesno
Loadingresolved before the code runsrequire runs when reached
Enable with"type": "module" or .mjsdefault, or .cjs

Use ES modules for new projects; this course does. Current Node versions can also require() most ES modules, and ES modules can import CommonJS packages, so mixing is usually possible.

Common mistakes#

Practice#

Practice exercise

Create temperature.js exporting toFahrenheit(c) and toCelsius(f) (rounded to 1 decimal), and an index.js that imports both and prints 37 °C in Fahrenheit and 212 °F in Celsius.

Show hint

export function toFahrenheit(c) { return Math.round((c * 9 / 5 + 32) * 10) / 10; }, and import with import { toFahrenheit, toCelsius } from "./temperature.js";.

Show solution
temperature.js (JavaScript)
export function toFahrenheit(c) {
  return Math.round(((c * 9) / 5 + 32) * 10) / 10;
}

export function toCelsius(f) {
  return Math.round((((f - 32) * 5) / 9) * 10) / 10;
}
index.js (JavaScript)
import { toCelsius, toFahrenheit } from "./temperature.js";

console.log(`37 °C = ${toFahrenheit(37)} °F`);
console.log(`212 °F = ${toCelsius(212)} °C`);
Terminal
node index.js
Output
37 °C = 98.6 °F
212 °F = 100 °C

Key takeaway#

Next: npm, package.json and Packages.

Finished this lesson?