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.
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.
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.
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);React Hook useCallback has a missing dependency: 'variable'. Either include it or remove the dependency array react-hooks/exhaustive-deps
React Hook useCallback has a missing dependency
Cannot use private fields in class components without TS support
Cannot use private fields in class components without TS support
Cannot destructure property 'xxx' of 'undefined'
Cannot destructure property of undefined when accessing props
useNavigate() may be used only in the context of a <Router> component.
useNavigate() may be used only in the context of a Router component
Cannot find module or its corresponding type declarations
How to fix "Cannot find module or type declarations" in Vite