The ECMAScript Module System in Node.js
14 min read·Jan 1, 2025
The ECMAScript module system is yet another way to package JavaScript code for Node.js.
Unlike CommonJS, ECMAScript modules align with the syntax used in frontend JavaScript environments, making it easier to write consistent code across server-side and client-side applications.
Moreover, ECMAScript modules load asynchronously by default, which can improve the efficiency of larger applications.
Note: Since CommonJS and ECMAScript modules handle imports and exports differently, mixing them in the same project may lead to compatibility issues and bugs. This is why it is usually recommended to choose one and stick to it.
Enabling the ECMAScript module system
CommonJS being the default module system in Node.js, you need to explicitly tell Node.js that you want to use the ECMAScript module system instead, either by creating JavaScript files with an .mjs file extension:
module.mjs
Or by creating a package.json file in the root directory of your project containing the following JSON object:
$ cat package.json
{
"type": "module"
}
Importing ECMAScript modules
To import an ECMAScript module into another file, you can use the global import...from statement:
import { identifier, ... } from source;
Where:
-
identifier, ...are the names of the variables, functions, and classes exported by the module that you want to import. -
sourceis either the name of a built-in or third-party module, or the path to a local module.
Example
In this example, Node.js will try to import the add and subtract components exported by the local calc.js module:
import { add, subtract } from './calc.js';
Importing and renaming components
To import and rename the components exported by a module — mostly to prevent naming collisions — you can use the as keyword:
import { identifier as new_identifier, ... } from source;
Example
In this example, Node.js will try to import the writeFileSync method exported by the core fs module as the write function:
import { writeFileSync as write } from 'node:fs';
Importing components as a single module
To import all the components exported by a module at once, you can use the import * as syntax:
import * as identifier from source;
Example
In this example, Node.js will automatically resolve the core fs module and assign its exported components to the fs variable:
import * as fs from 'node:fs';
Creating an ECMAScript module
To export one or more components, you can use the export statement with an object literal containing the names of these components:
variable = expression;
export {
variable,
...
};
Example
Let's consider this module, that exports two functions named add and subtract:
// File: calc.mjs
const add = (a, b) => a + b;
const subtract = (a, b) => a - b;
export { add, subtract };
Let's consider this script, that imports and uses the functions exported by the calc.js module:
// File: index.mjs
import * as calc from './calc.mjs';
console.log(calc.add(3, 1));
console.log(calc.subtract(3, 1));
Which will produce the following result:
$ node index.mjs
4
2
Specifying a default export
A default export is an ECMAScript module feature that allows a module to export a main, primary functionality.
To create a default export, you can use the export default statement:
export default expression;
To then import a component exported using a default export, you can use this syntax:
import identifier from source;
Example
Let's consider this module, that exports a single default function named calculator:
// File: calc.mjs
const calculator = (a, b, c) => {
if (c === '+') {
return a + b;
} else if (c === '-') {
return a - b;
}
return undefined;
};
export default calculator;
Let's consider this script, that imports and uses the default function exported by the calc.js module:
// File: index.mjs
import calculator from './calc.mjs';
console.log(calculator(1, 2, '+'));
console.log(calculator(2, 1, '-'));
Which will produce the following result:
$ node index.mjs
3
1
Mixing named and default exports
The ECMAScript module system allows you to mix named and default exports within the same module:
export { expression, ... };
export default expression;
This is useful when you want to make the main functionality of a module immediately accessible, while exposing auxiliary components, such as constants, for flexible use.
This allows you to selectively import the functionalities you need using one of the following syntaxes:
// Default import
import defaultIdentifier from source;
// Named import
import { namedIdentifier, ... } from source;
// Mixed import
import defaultIdentifier, { namedIdentifier, ... } from source;
Example
Let's consider this module, that contains two named exports and one default export:
// File: calc.mjs
const add = (a, b) => a + b;
const subtract = (a, b) => a - b;
const calculator = (a, b, c) => {
if (c === '+') {
return add(a, b);
} else if (c === '-') {
return subtract(a, b);
}
return undefined;
}
export { add, subtract };
export default calculator;
Let's consider this script, that imports and uses all functions (default and named) exported by the calc.js module:
// File: index.mjs
import calculator, { add, subtract } from './calc.mjs';
console.log(calculator(1, 2, '+'));
console.log(calculator(2, 1, '-'));
console.log(add(1, 2));
console.log(subtract(2, 1));
Which will produce the following result:
$ node index.mjs
3
1
3
1
Summary
Here's a summary of what you've learned in this lesson:
-
The ECMAScript module system is an alternative to the CommonJS module system.
-
The global
import {} fromstatement is used to import specific functionalities of a module. -
The global
import { as } fromstatement is used to import and rename specific functionalities of a module. -
The global
import * as fromstatement is used to import all the functionalities of a module. -
The global
exportstatement is used to export multiple functionalities at once. -
The global
export defaultstatement is used to export a single default functionality.
Enjoying the courses?
I've made these courses completely free so anyone can learn from them. If they've helped you and you'd like to actively support the work behind BackendBrewery, you can leave a tip:
Support BackendBrewery