Node.js ES Modules

ES Modules (ESM) are the official JavaScript way to share code between files. Browsers and Node.js both support them. You write import and export instead of require and module.exports.

Why Learn ES Modules

Modern libraries and tutorials use ESM. The syntax reads clearly and works the same in the browser and on the server. Learning it prepares you for current projects.

Two Module Styles in Node.js

+------------------------+--------------------------+
|   CommonJS (older)     |    ES Modules (modern)   |
+------------------------+--------------------------+
| require("fs")          | import fs from "fs"      |
| module.exports = x     | export default x         |
| File type: .js         | File type: .mjs or .js   |
+------------------------+--------------------------+

Turn On ES Modules

Node.js needs a signal that your file uses ESM. Pick one of two options.

Option 1: Use the .mjs Extension

Name your file app.mjs. Node.js treats it as an ES module.

Option 2: Set the Type in package.json

Add one line to your package.json file. Every .js file in the project then uses ESM.

{
  "name": "my-app",
  "type": "module"
}

Export Code

Named Exports

Named exports share several items from one file. Each item keeps its own name.

// math.js
export const PI = 3.14159;

export function add(a, b) {
  return a + b;
}

export function multiply(a, b) {
  return a * b;
}

Default Export

A default export shares one main item. Each file holds at most one default export.

// greet.js
export default function greet(name) {
  return "Hello, " + name;
}

Import Code

Import Named Items

Wrap named items in curly braces. The names must match the export names.

// app.js
import { add, multiply, PI } from "./math.js";

console.log(add(2, 3));       // 5
console.log(multiply(4, 5));  // 20
console.log(PI);              // 3.14159

Import a Default Item

Skip the curly braces for a default export. You choose any local name.

import greet from "./greet.js";
console.log(greet("Asha"));

Rename an Import

import { add as sum } from "./math.js";
console.log(sum(10, 20));

Import Everything

import * as math from "./math.js";
console.log(math.add(1, 2));

How Files Connect

 math.js                 greet.js
 export add              export default greet
 export multiply               |
 export PI                     |
      |                        |
      +-----------+------------+
                  |
                  v
               app.js
        import { add } from "./math.js"
        import greet from "./greet.js"

Rules to Remember

  • Write the full file extension in local imports, such as ./math.js.
  • Place import statements at the top level of the file.
  • Use the node: prefix for core modules, such as import fs from "node:fs".
  • Expect strict mode to run automatically in every ES module.

Replace __dirname in ESM

ES modules do not provide __dirname or __filename. Build them from import.meta.url.

import { fileURLToPath } from "node:url";
import path from "node:path";

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

console.log(__dirname);

Top-Level Await

ES modules allow await outside a function. This feature keeps small scripts short.

const response = await fetch("https://example.com/data.json");
const data = await response.json();
console.log(data);

Common Errors

Cannot use import statement outside a module

Node.js treats your file as CommonJS. Rename the file to .mjs or add the type setting to package.json.

require is not defined

ESM files do not support require. Switch to import for the same task.

Practice Tasks

  • Create a file with three math functions and export them by name.
  • Import two of them into another file and print the results.
  • Add a default export that returns a welcome message.