ES modules: export and import
A module is a file. Everything in it is private unless you export it, and other files get it with import. This is the modern system (ESM), understood by every browser, Node.js and bundler. Modules are strict mode by default, run once no matter how many files import them, and their imports are resolved before any code runs — which is why import must be at the top level.
// Named exports — as many as you like
export const PI = 3.14159
export function area(r) {
return PI * r * r
}
// A default export — one per file, imported under any name
export default function circumference(r) {
return 2 * PI * r
}
// Or export a list at the bottom
function helper() {}
export { helper as internalHelper }import circumference, { PI, area } from "./math.js" // default + named
import * as math from "./math.js" // everything, namespaced
import { area as circleArea } from "./math.js" // rename
console.log(PI, area(2), circumference(2), math.PI, circleArea(1))
// Lazy loading: import() returns a promise (Module 06)
const { default: heavy } = await import("./heavy-chart.js")
// Node built-ins use the node: prefix; packages use their bare name
import { readFile } from "node:fs/promises"
import express from "express"Relative paths need ./ and, in Node and browsers, the .js extension. Bundlers (Vite, webpack) relax that — but write it and everything works everywhere.
You should see
12.57 undefined
3SyntaxError: Cannot use import statement outside a module
// app.js, run with: node app.js
import { readFile } from "node:fs/promises"SyntaxError: Cannot use import statement outside a moduleNode treated the file as CommonJS (the old system) because nothing told it otherwise. In a browser, the same message appears when a <script> tag lacks type="module".
Node: add "type": "module" to package.json, or name the file .mjs. Browser: <script type="module" src="app.js">.
