Convert your CommonJS codebase to ES Modules with confidence.
Add "type": "module" to package.json
This makes all .js files ES Modules by default
Replace require() with import
Convert all CommonJS imports to ES Module syntax
Replace module.exports with export
Use named or default exports
Add .js extensions to imports
ES Modules require explicit file extensions
Replace __dirname and __filename
Use import.meta.url instead
Test thoroughly
Run your test suite and check for errors
❌ CommonJS (Before)
// utils.js
const helper = require('./helper');
function add(a, b) {
return a + b;
}
module.exports = { add };
✅ ES Modules (After)
// utils.js
import helper from './helper.js';
export function add(a, b) {
return a + b;
}
❌ Problem: Missing file extensions
import utils from './utils'; // Error!
✅ Solution: Add .js extension
import utils from './utils.js';
❌ Problem: __dirname not defined
const path = __dirname + '/file.txt'; // Error!
✅ Solution: Use import.meta.url
import { fileURLToPath } from 'url';
import { dirname } from 'path';
const __dirname = dirname(fileURLToPath(import.meta.url));
❌ Problem: Dynamic require()
const mod = require(`./${name}.js`); // Error!
✅ Solution: Use dynamic import()
const mod = await import(`./${name}.js`);
You can migrate gradually using the dual package approach:
package.json
{
"type": "module",
"exports": {
".": {
"import": "./dist/index.js",
"require": "./dist/index.cjs"
}
}
}
This allows your package to work with both CommonJS and ES Module consumers.