How to fix __dirname is not defined in ES module scope in React
This error occurs when using __dirname in ES modules (ESM), where CommonJS globals like __dirname are not available. Use import.meta.url with Node.js utilities to replicate __dirname functionality.
Quick fix
Fixes __dirname is not defined in ES module scope
import { fileURLToPath } from 'url';
import { dirname } from 'path';
import path from 'path';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
// Now you can use __dirname as before
const configPath = path.join(__dirname, 'config', 'settings.json');- Use import.meta.url with fileURLToPath (most compatible)
- Use import.meta.dirname in modern Node.js (v20.11+)
- Use new URL() for relative path resolution
- Update Vite configuration files
import { fileURLToPath } from 'url';import { dirname } from 'path';import path from 'path';const __filename = fileURLToPath(import.meta.url);const __dirname = dirname(__filename);// Now you can use __dirname as beforeconst configPath = path.join(__dirname, 'config', 'settings.json');__dirname is not defined in ES module scope
What this error means
This error appears when you try to use the __dirname global variable in an ES module (ESM) context. Unlike CommonJS modules, ES modules don't provide __dirname or __filename as built-in globals. This is a fundamental difference between the two module systems. In Vite projects, this commonly happens in configuration files (vite.config.js), Node.js scripts, or when using dependencies that weren't updated to support ESM. Vite uses ES modules by default, and any code using __dirname needs to be adapted to the ESM approach. The error is a ReferenceError because the JavaScript runtime simply doesn't recognize __dirname as a defined variable in the ES module scope. You need to manually recreate this functionality using import.meta.url, which is the ESM equivalent that provides information about the current module.
Typical symptoms
- Build fails with "ReferenceError: __dirname is not defined in ES module scope"
- Error occurs in vite.config.js or other configuration files
- Scripts using path.join(__dirname, ...) fail to execute
- Node.js process crashes when running development server
- Dependencies that rely on __dirname break during bundling
Common causes
- Using __dirname in a file with "type": "module" in package.json
- Using __dirname in a .mjs file or when Vite treats the file as ESM
- Migrating from CommonJS to ES modules without updating path resolution
- Dependencies in node_modules using __dirname that aren't transpiled by Vite
- Copying CommonJS code patterns into ESM configuration files
How to fix "__dirname is not defined in ES module scope"
Replace __dirname usage with import.meta.url combined with Node.js path utilities. This works in all Node.js versions that support ESM:
import { fileURLToPath } from 'url';
import { dirname } from 'path';
import path from 'path';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
// Now you can use __dirname as before
const configPath = path.join(__dirname, 'config', 'settings.json');This approach recreates both __filename and __dirname using ESM-compatible APIs.
If you're using Node.js v20.11 or later, you can use the built-in import.meta.dirname and import.meta.filename:
// No imports needed!
const __dirname = import.meta.dirname;
const __filename = import.meta.filename;
// Use directly
const configPath = path.join(__dirname, 'config', 'settings.json');This is the cleanest solution but requires a newer Node.js version. Check your version with node --version.
For simple file path resolution, use the URL constructor with import.meta.url directly:
// Resolve a file relative to current module
const configPath = new URL('./config/settings.json', import.meta.url);
// Convert to filesystem path if needed
import { fileURLToPath } from 'url';
const configFilePath = fileURLToPath(configPath);Many Node.js APIs accept URL objects directly, so you may not need to convert to a string path.
In vite.config.js, apply the fix at the top of the file:
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import { fileURLToPath } from 'url';
import { dirname, resolve } from 'path';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
export default defineConfig({
plugins: [react()],
resolve: {
alias: {
'@': resolve(__dirname, './src')
}
}
});This pattern is commonly needed for path aliases and custom plugin configurations.
If you need to keep using CommonJS, rename your config file to vite.config.cjs:
mv vite.config.js vite.config.cjsOr remove "type": "module" from package.json if it's set. However, this is not recommended as Vite and modern tooling prefer ESM.
{
"name": "my-app",
// Remove or comment out this line:
// "type": "module"
}Note: This approach goes against the modern JavaScript ecosystem trend toward ESM.
Advanced notes
ESM vs CommonJS module differences:
ES modules are the standard JavaScript module system, while CommonJS is Node.js's legacy system. Key differences affecting __dirname:
- CommonJS globals: Provides __dirname, __filename, require, module, and exports automatically
- ESM globals: Provides import.meta instead, which includes url, dirname (Node 20.11+), and filename (Node 20.11+)
Handling dependencies that use __dirname:
If a dependency in node_modules uses __dirname and breaks during Vite builds, you have limited options:
1. Check if the package has an ESM-compatible version
2. Use Vite's optimizeDeps.include to pre-bundle the dependency
3. Open an issue with the package maintainer to add ESM support
4. Fork and patch the dependency (last resort)
Performance considerations:
Using new URL() with import.meta.url is generally faster than fileURLToPath for simple path operations because it avoids URL-to-path conversion. Many Node.js file system methods now accept URL objects directly:
import { readFile } from 'fs/promises';
// Works without conversion!
const data = await readFile(new URL('./data.json', import.meta.url), 'utf-8');Create a reusable utility:
To avoid repetition, create a utility file:
// utils/path-helpers.js
import { fileURLToPath } from 'url';
import { dirname } from 'path';
export function getDirname(importMetaUrl) {
return dirname(fileURLToPath(importMetaUrl));
}
// Usage in any file:
import { getDirname } from './utils/path-helpers.js';
const __dirname = getDirname(import.meta.url);Frequently asked questions
- What does "__dirname is not defined in ES module scope" mean?
- This error appears when you try to use the __dirname global variable in an ES module (ESM) context. Unlike CommonJS modules, ES modules don't provide __dirname or __filename as built-in globals. This is a fundamental difference between the two module systems.
- How do I fix "__dirname is not defined in ES module scope"?
- This error occurs when using __dirname in ES modules (ESM), where CommonJS globals like __dirname are not available. Use import.meta.url with Node.js utilities to replicate __dirname functionality.
- What causes "__dirname is not defined in ES module scope"?
- Using __dirname in a file with "type": "module" in package.json Using __dirname in a .mjs file or when Vite treats the file as ESM Migrating from CommonJS to ES modules without updating path resolution
- Is the "__dirname is not defined in ES module scope" error serious?
- It is a medium-severity error โ more of a blocker than a risk. The steps above resolve it.
Official resources & further reading
- ๐React Official Documentation
- ๐Github.com - 6946(GitHub)
- ๐
- ๐
- ๐Vite.dev - features(Official Docs)
- ๐