__dirname is not defined error in Node.js 14 version
Categories:
Resolving '__dirname' Not Defined in Node.js ES Modules (Node 14+)

Understand why '__dirname' is unavailable in Node.js ES Modules and learn modern, compatible alternatives for path resolution.
Node.js 14 introduced robust support for ECMAScript Modules (ESM), bringing modern JavaScript module syntax (import
/export
) to the server-side. While this was a welcome change, it also brought a significant breaking change for many developers: the global variables __dirname
and __filename
are no longer directly available within ESM files. This article will explain why this change occurred and provide practical solutions to achieve equivalent functionality in your Node.js ESM projects.
The 'Why': CommonJS vs. ES Modules
The core reason __dirname
and __filename
are undefined in ES Modules stems from the fundamental differences between CommonJS (CJS) and ESM. CommonJS modules, which use require()
and module.exports
, execute synchronously and have a module
object and exports
variable implicitly available, along with __dirname
and __filename
.
ES Modules, on the other hand, are designed for asynchronous loading and static analysis. They operate in a different scope where these CommonJS-specific globals do not exist. This design choice promotes better interoperability with browser environments and allows for optimizations like tree-shaking.
flowchart TD A[Node.js Module System] --> B{Module Type?} B -- CommonJS --> C[__dirname, __filename available] B -- ES Modules --> D[__dirname, __filename NOT available] C --> E[Synchronous Loading] D --> F[Asynchronous Loading] D --> G[Static Analysis] G --> H[Tree Shaking]
Comparison of CommonJS and ES Module characteristics regarding global variables.
Modern Alternatives for Path Resolution
Fortunately, Node.js provides excellent alternatives to __dirname
and __filename
that are fully compatible with ES Modules. These solutions leverage the import.meta.url
property, which is a standard way to get the URL of the current module in ESM.
import.meta.url
returns a file://
URL. You'll need to convert it to a file system path using Node.js's url
module.Getting the Current File Path (__filename
equivalent)
To get the equivalent of __filename
in an ES Module, you can use import.meta.url
combined with fileURLToPath
from the node:url
module.
import { fileURLToPath } from 'node:url';
const __filename = fileURLToPath(import.meta.url);
console.log(__filename);
// Example output: /path/to/your/module.js
Emulating __filename
in an ES Module.
Getting the Current Directory Path (__dirname
equivalent)
Similarly, to get the equivalent of __dirname
, you'll use import.meta.url
, fileURLToPath
, and dirname
from the node:path
module.
import { fileURLToPath } from 'node:url';
import { dirname } from 'node:path';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
console.log(__dirname);
// Example output: /path/to/your
Emulating __dirname
in an ES Module.
Project Root Path Resolution
Often, __dirname
is used to resolve paths relative to the project root. While the above solutions work for the current file's directory, you might need a more robust way to find the project root, especially in complex projects or monorepos. A common approach is to find a known file like package.json
.
import { fileURLToPath } from 'node:url';
import { dirname, join } from 'node:path';
import { existsSync } from 'node:fs';
const currentFileDir = dirname(fileURLToPath(import.meta.url));
let projectRoot = currentFileDir;
while (!existsSync(join(projectRoot, 'package.json'))) {
const parentDir = dirname(projectRoot);
if (parentDir === projectRoot) {
// Reached file system root, package.json not found
throw new Error('package.json not found in parent directories.');
}
projectRoot = parentDir;
}
console.log('Project Root:', projectRoot);
// Example usage:
const configPath = join(projectRoot, 'config', 'app.json');
console.log('Config Path:', configPath);
Finding the project root by traversing up until 'package.json' is found.
Summary and Best Practices
The transition to ES Modules in Node.js requires adapting to new ways of handling path resolution. While __dirname
and __filename
are no longer available, import.meta.url
provides a powerful and standard-compliant alternative. By understanding the differences between CommonJS and ES Modules and utilizing the node:url
and node:path
modules, you can seamlessly manage file and directory paths in your modern Node.js applications.
Always prefer the import.meta.url
approach for new ES Module projects to ensure future compatibility and adherence to modern JavaScript standards.