Split Code Across Files With `import` and `export`
Modules
Modules let your code grow past one file. Each `.mjs` (or `"type":"module"` `.js`) is its own module.
What you'll learn
- Author and import an ES module
- Use named and default exports
- Know the file extension rules
Every JS file in Node is a module. Each has its own scope —
variables declared in one don’t leak into another. You expose values
with export, consume them with import.
A Module
// math.mjs
export function add(a, b) { return a + b; }
export const PI = 3.14159; Importing
// app.mjs
import { add, PI } from "./math.mjs";
console.log(add(2, 3)); // 5
console.log(PI); // 3.14159 Default Exports
// greeter.mjs
export default function greet(name) {
return `Hello, ${name}!`;
} import greet from "./greeter.mjs"; // any name, no braces
greet("Ada"); Both
// logger.mjs
export default function log(msg) { console.log(msg); }
export function warn(msg) { console.warn(msg); } import log, { warn } from "./logger.mjs"; File Extensions
In Node ESM, you must include the extension:
import { add } from "./math.mjs"; // ✓
import { add } from "./math"; // ✗ ERR_MODULE_NOT_FOUND (Bundlers like Vite/webpack are more forgiving, but raw Node isn’t.)
Importing Built-ins
Prefix Node built-ins with node::
import { readFileSync } from "node:fs";
import { join } from "node:path";
import { createServer } from "node:http"; The prefix is the modern, unambiguous way — never collides with an npm package of the same name.
Importing npm Packages
After npm install lodash:
import { chunk } from "lodash"; Node finds it in node_modules/. We cover npm next.
Up Next
ESM vs the older CommonJS — and why both exist.
ESM vs CJS →