Note: This post has been updated to reflect the latest changes in Node.js regarding __dirname and ES modules. See references: Node.js ESM docs, SonarSource blog.

__dirname is back in Node.js with ES modules

ECMAScript modules (ES modules) are now the standard for packaging JavaScript code. Node.js has moved from CommonJS to ES modules, and one major friction point—accessing the current module's directory—has finally been resolved.

TL;DR

In modern Node.js (v20.11.0+), you can use:

import.meta.dirname
import.meta.filename

See: Node.js ESM docs

Evolution: CommonJS to ES Modules

The old CommonJS way

__dirname  // The current module's directory name
__filename // The current module's file name

The old ES module workaround

Previously, ES modules did not have __dirname or __filename. You had to use:

import * as url from 'url';
const __dirname = url.fileURLToPath(new URL('.', import.meta.url));
const __filename = url.fileURLToPath(import.meta.url);

The new ES module way (Node.js v20.11.0+)

Now, you can simply use:

const __dirname = import.meta.dirname;
const __filename = import.meta.filename;

This removes the need for boilerplate and is the recommended approach for all new Node.js projects using ES modules.

Using URLs and Paths in Node.js ES Modules

Node.js APIs that accept file paths also accept URL objects. For example, to read a file relative to your module:

import { join } from 'node:path';
import { readFile } from 'node:fs/promises';

// Using import.meta.dirname (Node.js v20.11.0+)
const filePath = join(import.meta.dirname, 'data.json');
const data = await readFile(filePath, { encoding: 'utf8' });

// Or, using URL objects (works in all ES modules)
const fileUrl = new URL('data.json', import.meta.url);
const data2 = await readFile(fileUrl, { encoding: 'utf8' });

Using URL objects is especially useful for code that may run in both Node.js and browser environments, as it provides consistency.

Browser and REPL Caveats

  • import.meta.dirname and import.meta.filename are only available when the module is loaded from the file system (i.e., import.meta.url starts with file:). In browsers, these will be undefined.
  • The Node.js REPL does not support import.meta properties as of Node.js v21.x (StackOverflow).

References