Convert require() to import, and import back to require()

Paste a Node.js module and switch between CommonJS (require, module.exports) and ES modules (import, export) for the common one-line patterns, with notes on anything left unchanged.

Live demo · real result from this tool
Direction

Converted module

import fs from 'fs';import { join, resolve as resolvePath } from 'path';import { helper } from './helper';import 'dotenv/config'; function load(file) {  return fs.readFileSync(join(__dirname, file), 'utf8');} export { load, resolvePath };
Statements converted5

__dirname and __filename do not exist in ES modules; use import.meta.dirname / import.meta.filename (Node 20.11+) or fileURLToPath(import.meta.url).

Default-import interop differs: a CommonJS module imported with `import x from` gives you module.exports; named imports from CommonJS only work when Node can detect them statically.

Processed on your device — nothing is uploaded.

How to use the CommonJS ⇄ ESM converter

  1. Paste your module into the JavaScript box.
  2. Choose the Direction: CommonJS → ESM or ESM → CommonJS.
  3. Copy the Converted module. It downloads as module.mjs or module.cjs.
  4. 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 as module.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 import is only allowed at the top level. Move it to the top, or switch it to await import() by hand.
  • Interop is not identical. Importing a CommonJS module with import x from gives you its whole module.exports.
  • Top-level await and import.meta have no CommonJS equivalent; the tool notes both.

Frequently asked questions

Will Node run the converted ES module straight away?
Usually after small fixes. The file needs a .mjs extension or "type" set to "module" in package.json, relative imports need their file extension (./helper.js, not ./helper), and __dirname must be replaced. The tool keeps your paths exactly as written.
What replaces __dirname and __filename?
In ES modules use import.meta.dirname and import.meta.filename (Node 20.11 and later), or fileURLToPath(import.meta.url) on older versions. The tool adds a note whenever your code uses them.
Why is a conditional require not converted?
Static import must sit at the top level and always loads. A require inside an expression, such as a ternary, has no direct equivalent, so the line is left alone and listed in a note. Use await import() for those cases.
Does it work on multi-line statements?
Only partly. It reads one line at a time. A multi-line import is left unchanged with a note, and a multi-line module.exports = { … } object becomes export default { … }, a single default export rather than named exports.

Written by the ToolsRift team · Last updated

Pages are drafted with AI assistance and checked by automated tests. How we write and check pages.

Was this tool useful?

Report a problem

Start typing to search every tool.

↑ ↓ to moveEnter to openEsc to close