ยท new features
__dirname is not defined in ES module scope
Getting the __dirname is not defined error in your ES modules? Node.js now provides import.meta.dirname and import.meta.filename as native replacements, no workarounds needed.
If you've switched from CJS to ES modules in Node.js, you've likely encountered this error:
ReferenceError: __dirname is not defined in ES module scope.
This happens because __dirname and __filename are CommonJS globals that don't exist in ES modules.
There is a workaround involving fileURLToPath and dirname. But Node.js now provides native solutions with import.meta.dirname and import.meta.filename. Here's how to fix the error and use the modern approach.
Contents
Understanding the Error
In CommonJS modules, __dirname and __filename are automatically available:
console.log(__dirname); // /Users/you/project
console.log(__filename); // /Users/you/project/app.ctsBut when you use ES modules (files with .mts extension or "type": "module" in package.json), these globals don't exist:
console.log(__dirname);
// ReferenceError: __dirname is not defined in ES module scopeThis breaks code that relies on these values for file path operations, reading files relative to the current module, or resolving paths.
The Old Workaround
Before Node.js added native support, you had to recreate __dirname manually using import.meta.url:
import { fileURLToPath } from 'url';
import { dirname } from 'path';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
console.log(__dirname); // /Users/you/project
console.log(__filename); // /Users/you/project/app.mtsThis pattern appeared in countless ES module codebases. It worked, but required extra imports and boilerplate code just to get basic path information.
The Modern Solution
Node.js v20.11.0 and v21.2.0 introduced import.meta.dirname and import.meta.filename as direct replacements:
console.log(import.meta.dirname); // /Users/you/project
console.log(import.meta.filename); // /Users/you/project/app.mtsNo imports, no helper functions, no workarounds. These properties provide the exact same values you'd get from __dirname and __filename in CommonJS.
Practical Usage
Here are common scenarios where you'd use these properties:
Reading files relative to your module:
import { readFile } from 'node:fs/promises';
import { join } from 'node:path';
const configFile = join(import.meta.dirname, 'config.json');
const config = await readFile(configFile, 'utf-8');Resolving paths for imports or resources:
import { resolve } from 'node:path';
const templatesDir = resolve(import.meta.dirname, '..', '/templates');
console.log(templatesDir); // "/templates"Loading assets in a web server:
import { join } from 'node:path';
import { createReadStream } from 'node:fs';
const publicDir = join(import.meta.dirname, 'public');
const stream = createReadStream(join(publicDir, 'index.html'));