How to use the CommonJS ⇄ ESM converter
- Paste your module into the JavaScript box.
- Choose the Direction: CommonJS → ESM or ESM → CommonJS.
- Copy the Converted module. It downloads as
module.mjsormodule.cjs. - Read the notes under the result. They list lines that were not converted and runtime differences you need to handle.
What it does and when to use it
Node.js supports both module systems, and many projects are moving older require code to import so it matches front-end code and works with modern tooling. The reverse is useful when a tool or older Node version only loads CommonJS. Use this converter for a single file or a pasted snippet; for a large codebase, a codemod that understands the whole project is safer.
Afterwards, sort the new import block with the JS import sorter, check the syntax with the JavaScript validator, and modernise var with var to let / const.
How it works
Each line is matched against a set of patterns. Anything that does not match exactly is kept as written.
| CommonJS | ES module |
|---|---|
const fs = require('fs'); |
import fs from 'fs'; |
const { a, b: c } = require('m'); |
import { a, b as c } from 'm'; |
const h = require('./h').h; |
import { h } from './h'; |
require('dotenv/config'); |
import 'dotenv/config'; |
module.exports = { a, b }; |
export { a, b }; |
module.exports = main; |
export default main; |
exports.x = function () {…} |
export function x() {…} |
In the other direction, import * as ns becomes a require, a default plus named import becomes two lines, and export const, export function and export class keep their declaration and add exports.name = name; lines at the end. When the module also has a default export, those lines (and any export { … } lists) become module.exports.name = …; after the module.exports = line, so the named exports survive. Simple exports.a = a; lines are collected into one export { … } statement.
Worked examples
CommonJS to ESM. The default sample becomes:
import fs from 'fs';
import { join, resolve as resolvePath } from 'path';
import { helper } from './helper';
import 'dotenv/config';
with export { load, resolvePath }; at the end. Five statements were converted, and a note warns that __dirname does not exist in ES modules.
ESM to CommonJS. import { readFile as read } from 'node:fs/promises'; becomes const { readFile: read } = require('node:fs/promises');, and the exported VERSION and load get exports.VERSION = VERSION; and exports.load = load; at the bottom.
A conditional require. const lib = cond ? require('a') : require('b'); stays as it is, with the note “Left unchanged (dynamic or nested require)”. The two exports. lines below it become export { run, stop };.
Limits and tips
- Default plus named exports. Converting to CommonJS writes
module.exports = x;and then the named exports asmodule.exports.name = …;lines, so they land on the new object. That works when the default export is an object or a function; a note says so. - A require inside a function or block is left unchanged with a note, because
importis only allowed at the top level. Move it to the top, or switch it toawait import()by hand. - Interop is not identical. Importing a CommonJS module with
import x fromgives you its wholemodule.exports. - Top-level await and
import.metahave no CommonJS equivalent; the tool notes both.
Frequently asked questions
Will Node run the converted ES module straight away?
What replaces __dirname and __filename?
Why is a conditional require not converted?
Does it work on multi-line statements?
How do we know nothing is uploaded? Test it yourself on the privacy proof page.