Fix "__dirname is not defined in ES module scope" in JavaScript/Node

When making the switch from CommonJS modules to ES modules, there are a few differences you'll notice. One error you'll likely run into is "Uncaught ReferenceError: __dirname is not defined in ES module scope". This error is exactly what it sounds like, the global __dirname variable is not defined when using ES modules. This is also true for the global __filename variable.

To fix this, you'll have to use a workaround, described below.

The Workaround

To get the current file directory, we'll want to use a combination of a global variable and a few built-in methods:

  • import.meta.url to get the current file's as a URL
  • url.fileURLToPath to change the URL to a path
  • path.dirname to get the directory name

Using these methods, we can reconstruct the global __dirname and __filename variables that are available to use in CommonJS:

import path from 'path';
import url from 'url';

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

console.log(__filename);
console.log(__dirname);

// Prints:
// /Users/scott/sandbox/javascript/index.mjs
// /Users/scott/sandbox/javascript
Get free courses, guided projects, and more

No spam ever. Unsubscribe anytime. Read our Privacy Policy.

Arguably the most important part here is the import.meta.url global variable, which is what allows us to get the current file's URL, which can then be converted to a path. This is the closest equivalent to __filename that we have in ES modules.

Gotchas

One difficulty about doing it this way is that we can't simply polyfill the __dirname and __filename variables in the global scope. We need to create them in the module scope. This is because by setting these as global variables, or passing these variables around, they'll still point to the original file they were created in.

So what does this mean? We need to create these variables in every file in which they're used. While annoying, it's what we have to work with. To make things easier, you can create a helper method to reduce it into a single import and single function call:

import path from 'path';
import url from 'url';

export function currDir(fileUrl) {
    const __filename = url.fileURLToPath(fileUrl);
    return path.dirname(__filename);
}

Then you can easily use this helper method to get the current file's directory like this:

import { currDir } from './lib';

const __dirname = currDir(import.meta.url);

console.log(__dirname);

// Prints: /Users/scott/sandbox/javascript
Last Updated: April 12th, 2023
Was this helpful?

© 2013-2024 Stack Abuse. All rights reserved.

AboutDisclosurePrivacyTerms