Menu
×
   ❮     
HTML CSS JAVASCRIPT SQL PYTHON JAVA PHP HOW TO W3.CSS C C++ C# BOOTSTRAP REACT MYSQL JQUERY EXCEL XML DJANGO NUMPY PANDAS NODEJS DSA TYPESCRIPT ANGULAR GIT POSTGRESQL MONGODB ASP AI R GO KOTLIN SASS VUE GEN AI SCIPY CYBERSECURITY DATA SCIENCE INTRO TO PROGRAMMING BASH RUST

Node.js Tutorial

Node HOME Node Intro Node Get Started Node JS Requirements Node.js vs Browser Node Cmd Line Node V8 Engine Node Architecture Node Event Loop

Asynchronous

Node Async Node Promises Node Async/Await Node Errors Handling

Module Basics

Node Modules Node ES Modules Node NPM Node package.json Node NPM Scripts Node Manage Dep Node Publish Packages

Core Modules

HTTP Module HTTPS Module File System (fs) Path Module OS Module URL Module Events Module Stream Module Buffer Module Crypto Module Timers Module DNS Module Assert Module Util Module Readline Module

JS & TS Features

Node ES6+ Node Process Node TypeScript Node Adv. TypeScript Node Lint & Formatting

Building Applications

Node Frameworks Express.js Middleware Concept REST API Design API Authentication Node.js with Frontend

Database Integration

MySQL Get Started MySQL Create Database MySQL Create Table MySQL Insert Into MySQL Select From MySQL Where MySQL Order By MySQL Delete MySQL Drop Table MySQL Update MySQL Limit MySQL Join
MongoDB Get Started MongoDB Create DB MongoDB Collection MongoDB Insert MongoDB Find MongoDB Query MongoDB Sort MongoDB Delete MongoDB Drop Collection MongoDB Update MongoDB Limit MongoDB Join

Advanced Communication

GraphQL Socket.IO WebSockets

Testing & Debugging

Node Adv. Debugging Node Testing Apps Node Test Frameworks Node Test Runner

Node.js Deployment

Node Env Variables Node Dev vs Prod Node CI/CD Node Security Node Deployment

Perfomance & Scaling

Node Logging Node Monitoring Node Performance Child Process Module Cluster Module Worker Threads

Node.js Advanced

Microservices Node WebAssembly HTTP2 Module Perf_hooks Module VM Module TLS/SSL Module Net Module Zlib Module Real-World Examples

Hardware & IoT

RasPi Get Started RasPi GPIO Introduction RasPi Blinking LED RasPi LED & Pushbutton RasPi Flowing LEDs RasPi WebSocket RasPi RGB LED WebSocket RasPi Components

Node.js Reference

Built-in Modules EventEmitter (events) Worker (cluster) Cipher (crypto) Decipher (crypto) DiffieHellman (crypto) ECDH (crypto) Hash (crypto) Hmac (crypto) Sign (crypto) Verify (crypto) Socket (dgram, net, tls) ReadStream (fs, stream) WriteStream (fs, stream) Server (http, https, net, tls) Agent (http, https) Request (http) Response (http) Message (http) Interface (readline)

Resources & Tools

Node.js Compiler Node.js Server Node.js Quiz Node.js Exercises Node.js Syllabus Node.js Study Plan Node.js Certificate

Node.js ES Modules


Introduction to ES Modules

ES Modules (ESM) is the official standard format for packaging JavaScript code for reuse.

It was introduced in ES6 (ES2015) and is now supported in Node.js.

Prior to ES Modules, Node.js exclusively used the CommonJS module format (require/exports).

Now developers can choose between CommonJS and ES Modules based on their project needs.

ES Modules provides a more structured and statically analyzable way to work with modules compared to CommonJS, with benefits like tree-shaking for smaller builds.


CommonJS vs ES Modules

Here's how CommonJS and ES Modules differ:

Feature CommonJS ES Modules
File Extension .js (default) .mjs (or .js with proper config)
Import Syntax require() import
Export Syntax module.exports / exports export / export default
Import Timing Dynamic (runtime) Static (parsed before execution)
Top-level Await Not supported Supported
File URL in Imports Not required Required for local files

Example: CommonJS Module

// math.js (CommonJS)
function add(a, b) {
  return a + b;
}

function subtract(a, b) {
  return a - b;
}

module.exports = {
  add,
  subtract
};

// app.js (CommonJS)
const math = require('./math');
console.log(math.add(5, 3)); // 8

Example: ES Module

// math.mjs (ES Module)
export function add(a, b) {
  return a + b;
}

export function subtract(a, b) {
  return a - b;
}

// app.mjs (ES Module)
import { add, subtract } from './math.mjs';
console.log(add(5, 3)); // 8
Run example »

Enabling ES Modules

There are several ways to enable ES Modules in Node.js:

1. Using the .mjs File Extension

The simplest way is to use the .mjs extension for your files.

Node.js will automatically treat these files as ES Modules.

2. Setting "type": "module" in package.json

To use ES Modules with regular .js files, add the following to your package.json:

{
  "name": "my-package",
  "version": "1.0.0",
  "type": "module"
}

With this setting, all .js files in your project will be treated as ES Modules.

3. Using the --input-type=module Flag

For scripts run directly with the node command, you can specify the module system:

node --input-type=module script.js

Note: If you're working with a codebase that primarily uses CommonJS but you want to use ES Modules in one file, using the .mjs extension is the most explicit and least error-prone approach.



Import and Export Syntax

ES Modules provide more flexible ways to import and export code compared to CommonJS.

Export Syntax

Named Exports

// Multiple named exports
export function sayHello() {
  console.log('Hello');
}

export function sayGoodbye() {
  console.log('Goodbye');
}

// Alternative: export list at the end
function add(a, b) {
  return a + b;
}

function subtract(a, b) {
  return a - b;
}

export { add, subtract };

Default Export

// Only one default export per module
export default function() {
  console.log('I am the default export');
}

// Or with a named function/class/object
function mainFunction() {
  return 'Main functionality';
}

export default mainFunction;

Mixed Exports

// Combining default and named exports
export const VERSION = '1.0.0';

function main() {
  console.log('Main function');
}

export { main as default }; // Alternative way to set default

Import Syntax

Importing Named Exports

// Import specific named exports
import { sayHello, sayGoodbye } from './greetings.mjs';
sayHello(); // Hello

// Rename imports to avoid naming conflicts
import { add as sum, subtract as minus } from './math.mjs';
console.log(sum(5, 3)); // 8

// Import all named exports as an object
import * as math from './math.mjs';
console.log(math.add(7, 4)); // 11

Importing Default Exports

// Import the default export
import mainFunction from './main.mjs';
mainFunction();

// You can name the default import anything you want
import anyNameYouWant from './main.mjs';
anyNameYouWant();

Importing Both Default and Named Exports

// Import both default and named exports
import main, { VERSION } from './main.mjs';
console.log(VERSION); // 1.0.0
main(); // Main function
Run example »

Dynamic Imports

ES Modules support dynamic imports, allowing you to load modules conditionally or on-demand.

Example: Dynamic Imports

// app.mjs
async function loadModule(moduleName) {
  try {
    // Dynamic import returns a promise
    const module = await import(`./${moduleName}.mjs`);
    return module;
  } catch (error) {
    console.error(`Failed to load ${moduleName}:`, error);
  }
}

// Load a module based on a condition
const moduleName = process.env.NODE_ENV === 'production' ? 'prod' : 'dev';

loadModule(moduleName).then(module => {
  module.default(); // Call the default export
});

// Or with simpler await syntax
(async () => {
  const mathModule = await import('./math.mjs');
  console.log(mathModule.add(10, 5)); // 15
})();
Run example »

Use Case: Dynamic imports are great for code-splitting, lazy-loading modules, or conditionally loading modules based on runtime conditions.


Top-level Await

Unlike CommonJS, ES Modules support top-level await, allowing you to use await outside of async functions at the module level.

Example: Top-level Await

// data-loader.mjs
// This would cause an error in CommonJS or in a script
// But works at the top level in an ES Module

console.log('Loading data...');

// Top-level await - the module's execution pauses here
const response = await fetch('https://jsonplaceholder.typicode.com/todos/1');
const data = await response.json();

console.log('Data loaded!');

export { data };

// When another module imports this one, it will only get the exports
// after all the top-level await operations have completed
Run example »

Top-level await is especially useful for:

  • Loading configuration from files or remote sources
  • Connecting to databases before exporting functionality
  • Conditional imports or module initialization

Best Practices

When working with ES Modules in Node.js, follow these best practices:

1. Be Clear About File Extensions

Always include file extensions in your import statements for local files:

// Good
import { someFunction } from './utils.mjs';

// Bad - might not work depending on configuration
import { someFunction } from './utils';

2. Use Directory Indexes Properly

For directory imports, create index.mjs files:

// utils/index.mjs
export * from './string-utils.mjs';
export * from './number-utils.mjs';

// app.mjs
import { formatString, add } from './utils/index.mjs';

3. Choose the Right Export Style

Use named exports for multiple functions/values, and default exports for main functionality:

// For libraries with many utilities, use named exports
export function validate() { /* ... */ }
export function format() { /* ... */ }

// For components or classes that are the primary export
export default class UserService { /* ... */ }

4. Handle the Transition from CommonJS

When working with a codebase that mixes CommonJS and ES Modules:

  • ES Modules can import from CommonJS modules using default import
  • CommonJS can require() ES Modules only with dynamic import()
  • Use the compatibility helpers in the Node.js 'module' package for interoperability
// Importing CommonJS module from ESM
import fs from 'fs'; // The default import is module.exports

// Importing ESM from CommonJS (Node.js 12+)
// In a CommonJS module:
(async () => {
  const { default: myEsmModule } = await import('./my-esm-module.mjs');
})();

5. Dual Package Hazard

For npm packages that support both module systems, use the "exports" field in package.json to specify different entry points:

{
  "name": "my-package",
  "exports": {
    ".": {
      "import": "./index.mjs",
      "require": "./index.cjs"
    }
  }
}

Node.js Support: ES Modules are fully supported in Node.js since v12, with better support in v14+.

For older versions, you may need a transpiler like Babel.




×

Contact Sales

If you want to use W3Schools services as an educational institution, team or enterprise, send us an e-mail:
sales@w3schools.com

Report Error

If you want to report an error, or if you want to make a suggestion, send us an e-mail:
help@w3schools.com

W3Schools is optimized for learning and training. Examples might be simplified to improve reading and learning. Tutorials, references, and examples are constantly reviewed to avoid errors, but we cannot warrant full correctness of all content. While using W3Schools, you agree to have read and accepted our terms of use, cookie and privacy policy.

Copyright 1999-2025 by Refsnes Data. All Rights Reserved. W3Schools is Powered by W3.CSS.