tezvyn:

ES Modules in Node.js: The Modern `import` System

AI-drafted, machine-checkedSource: nodejs.orgintermediate

ES Modules bring the browser's `import`/`export` syntax to Node.js, replacing the classic `require()`. Use ESM for modern projects to get features like top-level await. The main footgun is that you can't use `require()`, `__dirname`, or `__filename`.

WHY IT EXISTS JavaScript originally lacked a standard module system. Node.js created its own, CommonJS (CJS), using require(). Later, the official ECMAScript standard introduced ES Modules (ESM) with import and export. Node.js adopted ESM to align with the broader JavaScript ecosystem, improve static analysis, and enable modern features.

THE MENTAL MODEL Think of ESM as a statically analyzable contract. The import and export statements are rigid and declared at the top level, allowing tools and the runtime to map out your project's dependency graph before executing any code. This is a major shift from CommonJS, where require() is a dynamic function that can be called anywhere, making dependency resolution a runtime operation.

HOW IT WORKS Node.js will treat files as ES modules if the nearest parent package.json contains "type": "module", or if the files have a .mjs extension. Imports are handled asynchronously. Unlike CJS, you cannot use globals like require, exports, module.exports, __filename, or __dirname. To get the current file's path, you use import.meta.url. File extensions in import paths (e.g., ./my-module.js) are mandatory for relative imports.

WHEN TO USE IT Use ESM for all new Node.js applications and libraries. It is the modern standard and the direction the ecosystem is heading. It unlocks powerful features like top-level await, which can significantly simplify asynchronous initialization logic in your application's entry point. It also makes your code more portable between Node.js and browser environments.

WHEN NOT TO USE IT Be cautious when migrating a large, stable CommonJS codebase. The shift can be complex, especially if the code relies heavily on dynamic require() calls or monkey-patching require.cache. If you depend on older tooling that doesn't fully support ESM, sticking with CommonJS might be necessary until the tooling is updated.

ONE CANONICAL EXAMPLE To enable ESM, first add "type": "module" to your package.json. Then your files can use the import/export syntax.

// utils.js export const greet = () => 'Hello from an ES Module!';

// server.js import { greet } from './utils.js';

const message = greet(); console.log(message); // Prints 'Hello from an ES Module!'

Note the explicit ./utils.js file extension in the import statement, which is required in ESM.

Read the original → nodejs.org

Get five bites like this every day.

Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.