How to convert CommonJS modules to ES modules in Node.js

Older Node.js projects often keep CommonJS files beside code that already uses import and export. Converting one module pair at a time keeps the migration small, lets existing tests catch behavior changes, and makes the runtime boundary clear before more files depend on it.

A package-level conversion uses package.json with "type": "module" so converted .js files run as ES modules. Files that still need require() or module.exports should stay on the .cjs extension until they are converted.

ES modules require explicit relative file extensions, and CommonJS locals such as require, module.exports, filename, and dirname are not available as local bindings. Convert the import and export syntax deliberately, then run the project smoke or test script against the converted entry point.

Steps to convert CommonJS modules to ES modules in Node.js:

  1. Run the current CommonJS entry point before changing module syntax.
    $ node src/app.js
    total=107
  2. Set the project package to ES module mode.
    package.json
    {
      "name": "module-convert-commonjs-esm",
      "version": "1.0.0",
      "type": "module",
      "scripts": {
        "smoke": "node src/app.js"
      }
    }

    After "type": "module" is set, .js files in the package run as ES modules. Keep unconverted CommonJS files on .cjs or convert them before they are loaded.

  3. Replace the CommonJS export with a named ES module export.
    src/price.js
    export function totalWithTax(subtotal, taxRate) {
      return Number((subtotal * (1 + taxRate)).toFixed(2));
    }
  4. Replace the CommonJS require() call with an import statement that includes the file extension.
    src/app.js
    import { totalWithTax } from "./price.js";
     
    console.log(`total=${totalWithTax(100, 0.07)}`);

    Relative ES module imports in Node.js need the target file extension, such as ./price.js.

  5. Run the converted smoke script.
    $ npm --silent run smoke
    total=107