Resolve “__dirname Is Not Defined” in Node.js
If you’ve switched your Node.js project to ES modules ("type": "module"), you may be surprised to see this error:
ReferenceError: __dirname is not defined in ES module scopeThis happens because unlike CommonJS, ES modules don’t include globals like __dirname and __filename.
This guide explains why this occurs, how to recreate these globals safely, and modern best practices for working with file paths in Node.js.
Why __dirname Doesn’t Exist in ES Modules
CommonJS provides:
-
__filename→ full file path -
__dirname→ directory of the current module
But ES modules use URL-based resolution instead of file globals.
This design keeps Node.js consistent with browser modules.
Thus, in ESM, you must derive the path manually using:
-
import.meta.url -
fileURLToPath() -
path.dirname()
Fix 1 — Recreate __dirname and __filename Manually (ESM-Safe)
This is the official Node.js recommendation.
import { dirname } from 'path';
import { fileURLToPath } from 'url';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
console.log(__filename);
console.log(__dirname);Why this works:
-
import.meta.url→ full URL of current ES module -
fileURLToPath()→ converts URL → filesystem path -
dirname()→ extracts directory
This behaves identically to the CommonJS globals.
Fix 2 — Create a Reusable Utility (Recommended)
Instead of repeating the boilerplate in every file, create a helper:
utils/path.js
import { dirname } from 'path';
import { fileURLToPath } from 'url';
export function getDirname(meta) {
return dirname(fileURLToPath(meta.url));
}
export function getFilename(meta) {
return fileURLToPath(meta.url);
}Usage:
import { getDirname } from './utils/path.js';
const __dirname = getDirname(import.meta);
console.log(__dirname);This keeps your code clean and portable.
Fix 3 — Switch Back to CommonJS
If you don’t need ES modules, remove "type": "module":
{
"type": "commonjs"
}Now Node.js automatically restores __dirname and __filename.
Fix 4 — Using import.meta.resolve() (Node 20+ New API)
Node 20 introduced an improved module resolution API.
Example:
import { resolve } from 'import-meta-resolve';
import { dirname } from 'path';
const resolved = await resolve('./file.txt', import.meta.url);
const __dirname = dirname(resolved);This is powerful for working with relative imports inside ESM.
Fix 5 — Use process.cwd() When Appropriate
When dealing with project-level paths, you may not need __dirname at all:
const root = process.cwd();
console.log(root);Use when:
- working with config files
- reading files relative to the project root
- building CLIs
Avoid using it as a replacement for module-specific paths.
Fix 6 — Working With Webpack, Rollup, Vite, and Bundlers
Webpack
Disable Webpack from mocking Node globals:
node: {
__dirname: false,
__filename: false
}Vite
Use the built-in import.meta.url:
new URL('./file.txt', import.meta.url).pathname;Rollup
Define globals manually:
import replace from '@rollup/plugin-replace';
export default {
plugins: [
replace({
preventAssignment: true,
__dirname: JSON.stringify('/src'),
__filename: JSON.stringify('/src/index.js'),
}),
]
};Fix 7 — Modern ESM Path Techniques (Cleaner Alternatives)
1. URL-style resolution (portable across Node + browsers)
const filePath = new URL('./config.json', import.meta.url);2. Read file from ESM with fs/promises
import { readFile } from 'fs/promises';
const config = JSON.parse(
await readFile(new URL('./config.json', import.meta.url), 'utf8')
);3. Absolute path building
import path from 'path';
const assets = path.join(__dirname, 'assets');Common Mistakes to Avoid
1. Using __dirname directly in ESM
console.log(__dirname); // Error!2. Using path.resolve('./') expecting module directory
It resolves relative to cwd, not the file.
3. Mixing CommonJS require() with ESM
This causes resolution inconsistencies.
Quick Reference Table
| API | Works in ESM? | Purpose |
|---|---|---|
__dirname | ❌ | CommonJS-only module dir |
__filename | ❌ | CommonJS-only module file |
import.meta.url | ✅ | URL path of module |
fileURLToPath() | ✅ | Convert URL → file path |
process.cwd() | ✅ | Current working directory |
new URL() | ✅ | Browser-compatible file resolution |
Summary
To fix “ReferenceError: __dirname is not defined in ES module scope”:
- Recreate it manually using
import.meta.url&fileURLToPath(). - Use a utility wrapper for cleaner code.
- Remove
"type": "module"if you prefer CommonJS. - Use bundler-specific solutions for browser builds.
- Leverage modern ESM APIs like
new URL()andimport.meta.resolve().
With these tools, you can confidently manage file paths in modern Node.js and avoid breaking changes across module systems.