ECMAScript Modules in Node.js: New Plan

Original author: Axel Rauschmayer
  • Transfer

The current status of ECMAScript module support (ESM) in Node.js:

  • Experimental ESM support was added to Node.js 8.5.0 on September 12, 2017.
  • After that, the Technical Steering Committee of Node.js formed a team responsible for the Modules Team to help design the missing parts for the upcoming (non experimental) release. This team consists of people from various branches of web development (frontend, backend, JS engines, etc.).

In October, the Modules Team published a "Plan for the Implementation of New Modules . " This post explains what it contains.


The process is divided into three phases:

  • Phase 1: create a "minimal" core - the basic set of rules and capabilities, minimal and indisputable, as far as possible.
  • Phase 2 and Beyond: Creating more complex functionality based on the kernel.

The minimum core will be the basis for future work. The new design will also replace the current experimental implementation as soon as it acquires similar capabilities.

Phase 1: Minimum ESM Support Core in Node.js

Simplify Module Ids

One of the goals of the Modules Team is to achieve "browser equivalence" : Node.js should be as close to the browser behavior as possible. The kernel achieves this by simplifying the parsing of module identifiers (URLs pointing to modules):

  • Each module identifier must end with a file name with extension. I.e
    • Extensions are not added automatically.
    • Importing directories is not supported (either by redirecting to dir/index.mjsor reading the field mainin package.json).
  • ES modules can import embedded Node.js modules ( pathand the like). They are the only exception to the previous rule.
  • Only files with an extension are supported by default .mjs(see Phase 2 if you are interested in the status of other extensions). Thus, other types of modules cannot be imported via import: CommonJS modules, JSON files, native modules.

Bringing important CommonJS features to ES modules


  • ES modules will be able to import CommonJS modules via createRequireFromPath(). This will work as follows (there are plans to make an abbreviated method, for example, a function createRequireFromUrl()):

import {createRequireFromPath as createRequire} from 'module';
import {fileURLToPath as fromPath} from 'url';
const require = createRequire(fromPath(import.meta.url));
const cjsModule = require('./cjs-module.js');

  • CommonJS modules will be able to load ES modules via import().

Phase 2 and Future Plans

  • In the second phase we are waiting for:
    • Support for "bare" identifiers such as 'lodash'. Most likely, this will include some way of mapping these identifiers into real paths.
    • Support for other file extensions besides .mjs. This includes including support for ES modules in .jsfiles.
  • Phase 3 is likely to focus on module loaders with extension points where users can connect their logic.

When can I use ES modules in Node.js?

  • For the flag: available now
    • Warning: the behavior is not as described above in phase 1 (as of Node.js 11.5.0)
  • Without a flag and in accordance with phase 1: Modules The team tries to make this possible as soon as possible. We hope that the modules will be released from under the flag in Node.js 14 (April 2020) and will be ported to previous versions, if possible.

Frequently asked Questions

  • Why do you need a new file extension .mjs?
    • Each solution for distinguishing between ESM and CommonJS formats has its advantages and disadvantages. Using a separate resolution seems like a good option ( more info ).
  • Why should the behavior of Node.js look like a browser?
    • Because it makes it possible to reuse the code. For example, to create libraries that work simultaneously in browsers and in Node.js
    • It should also facilitate switching between the backend and the frontend during coding.
  • Why all these limitations for compatibility?
    • Between ES and CommonJS-modules there are quite strong differences in the structure (static versus dynamic) and the method of loading (asynchronous versus synchronous). Restrictions help to keep things simple - given that in the long run, the overwhelming majority will be ES modules.
  • Why is it all lasting so long?
    • There are many stakeholders involved and many different platforms involved (Node.js, npm, browsers, JS engines, TypeScript, TC39, and others). If we really get ES-modules that can work everywhere, it's probably worth the wait, IMHO.


Thanks to Miles Borins for his feedback on this post.

Additional sources for further reading

Also popular now: