Menu

How to Use ES Modules in a CommonJS Node Project (Without Breaking Everything)

How to Use ES Modules in a CommonJS Node Project (Without Breaking Everything)

So you’ve got a stable Node.js project, you’re happy using require(), and then you install a new package and get hit with:

Error [ERR_REQUIRE_ESM]: require() of ES Module not supported

If you’re like most devs, your first thought is: “Wait... do I have to rewrite my whole project?”

The short answer: not necessarily. Here's what’s going on, and how to handle it without tearing your codebase apart.

What’s the Issue?

Modern packages like lighthouse, node-fetch, and others are now shipping as ES Modules only. That means they require the use of import/export syntax instead of the older require() and module.exports.

The problem? Node doesn’t let you mix CommonJS and ESM unless you jump through some hoops. If your codebase is using CommonJS and you try to require() a module that only supports ESM Node throws a tantrum. Instantly.

You might think switching everything over is simple, but…not really. Especially if your project is a few years old, or has a bunch of interconnected files. Even one outdated package can turn the whole thing into a game of dependency whack-a-mole.

Option 1: Convert Your Project to ESM

You can migrate your whole codebase to ESM. To do that, you add this to your package.json:

"type": "module"

Then go file by file, updating all require() and module.exports statements into import/export. For example:

// Old
const fs = require('fs');

// New
import fs from 'fs';

It’s straightforward in theory, but depending on how big your project is, this can take hours, or days. And if you're using any tools, test runners, or libraries that still expect CommonJS, they might just break. So yeah...clean, but risky if you're mid-sprint or dealing with older dependencies.

Option 2: Use Dynamic import()

Now this one’s sneaky useful. If you only need to use one or two ESM-only libraries (like lighthouse, for example), you don’t need to refactor the whole house. You can just dynamically import() the module like this:

(async () => {
  const lighthouse = await import('lighthouse');
  // Use lighthouse here
})();

It works in CommonJS files and lets you sidestep the whole "type": "module" thing. But yeah, the function has to be async, which means if you're working inside a tight non-async setup, you'll have to juggle a bit. Still, this is probably the fastest fix with the least amount of regret.

Option 3: Use the CLI Instead (When Applicable)

If the library you're trying to use has a command line interface, you can just run it as a separate process. For example, lighthouse has a great CLI. So you can call it like this from your CommonJS project:

const { exec } = require('child_process');

exec('lighthouse https://example.com --output=json', (err, stdout, stderr) => {
  if (err) {
    console.error('Error:', stderr);
    return;
  }

  console.log('Lighthouse output saved.');
});

This is perfect for one-off utilities, background scripts, or internal tools. Downside? You're not really "using" the library programmatically, you're just shelling out to it. So you lose some flexibility. But honestly, if you're just looking to get results and move on, it's clean and reliable.

Final Thoughts

Node.js is moving toward ESM. That’s where the ecosystem is heading. But if you’re working in a legacy or mixed environment, you don’t have to fry your setup just to stay current.

Use import() when you can, lean on the CLI when it makes sense, and only fully convert to ESM if you’re ready to commit to the shift.

The key here is don’t panic. The error message looks dramatic, but in most cases, there’s a clean workaround that doesn’t require rewriting your entire codebase in a caffeine-fueled weekend binge.

Walter Guevara is a Computer Scientist, software engineer, startup founder and previous mentor for a coding bootcamp. He has been creating software for the past 20 years.
AD: "Heavy scripts slowing down your site? I use Fathom Analytics because it’s lightweight, fast, and doesn’t invade my users privacy." - Get $10 OFF your first invoice.

Community Comments

No comments posted yet

Code Your Own Classic Snake Game – The Right Way

Master the fundamentals of game development and JavaScript with a step-by-step guide that skips the fluff and gets straight to the real code.

Ad Unit

Current Poll

Help us and the community figure out what the latest trends in coding are.

Total Votes:
Q:
Submit

Add a comment