I ran into “__dirname is not defined in ES module scope” (Fixed)

People studying in an old but beautiful library
Photo by Oscar Ovalle. Source: Pexels

The error “__dirname is not defined in ES module scope” means you’re using __dirname global variable in an ES (ECMAScript) module.

Here’s what the error look like:

 file:///home/dwd/sandbox/utils.js:2
 return __dirname
 ^

ReferenceError: __dirname is not defined in ES module scope
This file is being treated as an ES module because it has a '.js' file extension and '/home/dwd/sandbox/package.json' contains type: module. To treat it as a CommonJS script, rename it to use the '.cjs' file extension.
  at getDirName (file:///home/dwd/sandbox/utils.js:2:3)
  at file:///home/dwd/sandbox/index.js:3:13
  at ModuleJob.run (node:internal/modules/esm/module_job:193:25)
  at async Promise.all (index 0)
  at async ESMLoader.import (node:internal/modules/esm/loader:541:24)
  at async loadESM (node:internal/process/esm_loader:91:5)
  at async handleMainPromise (node:internal/modules/run_main:65:12)

Node.js v18.7.0 

What does __ dirname mean in Node? You may ask.

The __dirname global variable contains the path to the current module's directory.

The global variables __dirname and __filename only exist in CommonJS modules and aren't available in ES modules.

So if you've enabled ES modules in Node.js (via "type": "module" in package.json) or using ES modules through a module bundler like Webpack, you'll no longer have access to these global variables.

The error "ReferenceError: __dirname is not defined in ES module scope" is one of the most common errors developers face when switching from CommonJS modules to ES modules.

The workaround is quite easy, though. Here's how it's done:

  1. Get the module file URL from the import.meta object
  2. Convert the URL to a path by fileUrlToPath()
  3. Get the module's directory by using the path.dirname() method
 import { fileURLToPath } from 'url';
import path from 'path';

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename); 

The import.meta object exposes context-specific metadata to a JavaScript module, including the module's URL.

Whenever you need the __dirname value, you'll have to repeat the above instructions. It's better to create a helper function.

Create a helper function to emulate __dirname functionality in your app

You can create a helper function, which you can call anytime you need the __dirname value.

  • utils.js
 import path from 'path'
import { fileURLToPath } from 'url'

const getDirName = function (moduleUrl) {
    const filename = fileURLToPath(moduleUrl)
    return path.dirname(filename)
}

export {
    getDirName
} 

And use it like so:

  • moduleA.js
 // ModuleA.js
import { getDirName } from './libs/utils'

// Getting the dirname of moduleA.js
const dirName = getDirName(import.meta.url)

console.log(dirName)
// output: /home/dwd/sandbox/modules 

Please note you'll have to provide the import.meta.url when calling the function; If you refer to it from inside the lib.js module, it'll return the utils.js directory name (/home/dwd/sandbox/libs).

I hope this guide was helpful.

Thanks for reading.

Author photo

Hey 👋 I'm a software engineer, an author, and an open-source contributor. I enjoy helping people (including myself) decode the complex side of technology. I share my findings on Twitter: @lavary_

If you read this far, you can tweet to the author to show them you care. Tweet a Thanks

In this article:

Disclaimer: This post might contain affiliate links. I might receive a commission if a purchase is made. However, it doesn’t change the cost you’ll pay.