JavaScript Modules

JavaScript modules let you split code into separate files that export what they share and import what they need. ES modules (ESM) are the standard module system in browsers and Node.js.

Named Exports

A file can export any number of named values. Import them with the same names inside braces, optionally renaming with as.

// math.js
export const PI = 3.14159;
export function area(r) {
  return PI * r * r;
}

// main.js
import { area, PI as pi } from "./math.js";
console.log(area(2).toFixed(2), pi);
12.57 3.14159

Default Exports

A file can have one default export, imported with any name and without braces. Many projects prefer named exports because they are easier to search and refactor.

// logger.js
export default function log(msg) {
  console.log("[app]", msg);
}

// main.js
import log from "./logger.js";
log("started");
[app] started

Using Modules in the Browser and Node.js

  • Browser: <script type="module" src="main.js"></script>
  • Module scripts are deferred and run in strict mode automatically
  • Imports need a file path with extension in the browser, e.g. ./math.js
  • Node.js: use .mjs files or set "type": "module" in package.json
  • Bundlers like Vite also resolve package names like import React from "react"

Dynamic import()

import() loads a module on demand and returns a promise. Use it to load heavy code only when needed. This example imports a module from a data URL so it runs in a single file.

const source = "export const greet = (n) => 'Hi ' + n;";
const url = "data:text/javascript," + encodeURIComponent(source);

import(url).then((mod) => {
  console.log(mod.greet("module"));
});
Hi module

Module Scope

Top-level variables in a module are private to that module; they do not become globals. Modules also support top-level await, so you can await a fetch directly at the top of a module file.

Frequently asked questions

What is the difference between default and named exports?

A module has at most one default export, imported without braces under any name. Named exports must be imported by their exact name in braces.

Why do I get "Cannot use import statement outside a module"?

The file is not loaded as a module. Add type="module" to the script tag, or set "type": "module" in package.json for Node.js.

What is the difference between require and import?

require is CommonJS, the older Node.js system, and loads synchronously. import is the ES module standard used by browsers and modern Node.