Node.jsのESモジュールで「ReferenceError: __dirname is not defined」を解決する方法

初級💚 Node.js2026-05-19| Node.js (v14.13.0+, v16.x, v18.x, v20.x+), macOS, Linux, Windows

Error Message

ReferenceError: __dirname is not defined in ES module scope
#nodejs#esm#javascript#__dirname#backend

なぜ __dirname が消えたのか?最近 Node.js プロジェクトで requireimport に切り替えた場合、壁に突き当たったかもしれません。現在のディレクトリにアクセスしようとすると、Node.js が ReferenceError をスローします。これは、ESモジュール(ESM)がデフォルトで __dirname__filename などのグローバル変数を含んでいないためです。

CommonJS ではこれらの変数が自動的に提供されます。しかし、ESM はプラットフォームに依存しないように設計されています。ブラウザにはサーバーのような「ディレクトリ構造」が存在しないため、異なる環境間での ESM の一貫性を保つために、これらのグローバル変数は削除されました。Node.js 14 以降を使用している場合は、これらのパスを手動で再構築する必要があります。

解決策:import.meta.url を使用するパスを取得するには、import.meta.url を使用する必要があります。このプロパティは、file:///Users/dev/project/index.js のように、現在のモジュールの完全な URL を返します。その後、Node.js の組み込みユーティリティを使用して、この URL を標準のファイルパスに変換できます。

1. path モジュールと url モジュールをインポートするまず、ファイル URL とパス文字列を処理するために必要なツールを取り込みます。スクリプトの先頭に以下の行を追加してください。

import { fileURLToPath } from 'url';
import { dirname } from 'path';

2. 欠落しているグローバル変数を再現するわずか2行のコードで、__filename__dirname を手動で定義できます。これにより、ESM コードでも従来と同じ感覚でパスを扱えるようになります。

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);

3. すべてを組み合わせるスクリプトからの相対パスで config フォルダを指定する場合の、一般的なセットアップ例を以下に示します。

import path from 'path';
import { fileURLToPath } from 'url';

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

// 例:設定ファイルのパスを結合する
const configPath = path.join(__dirname, 'config', 'settings.json');
console.log(`ターゲットパス: ${configPath}`);

修正のテストapp.mjs(または package.json"type": "module" が設定されている場合は app.js)という名前のファイルを作成して、解決策を確認します。上記のロジックを貼り付けて実行してください。

node app.mjs

ターミナルにファイルとフォルダの絶対パスが表示されるはずです。これで ReferenceError は発生しません。

ESM ファイルパスに関するヒント### process.cwd() だけに頼らないショートカットとして process.cwd() を使いたくなるかもしれません。しかし、注意が必要です。process.cwd() はスクリプトが存在する場所ではなく、ターミナルコマンドを実行したディレクトリを返します。ルートフォルダから node ./src/app.js を実行した場合、process.cwd()__dirname は異なる場所を指すことになります。

JSON ファイルを安全に読み込む多くの開発者は JSON ファイルを読み込むために __dirname を必要とします。最新の Node.js バージョン(v20.10+)では JSON の Import Attributes がサポートされていますが、古い LTS バージョンでは fs モジュールと __dirname の修正を組み合わせる方法が最も互換性の高い手法です。

import { readFileSync } from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';

const __dirname = path.dirname(fileURLToPath(import.meta.url));
const rawData = readFileSync(path.join(__dirname, 'data.json'), 'utf8');
const data = JSON.parse(rawData);

パスのロジックを共通化するプロジェクトに多数のファイルがある場合、これらの行を繰り返すのは面倒です。import.meta.url は呼び出されたファイルによって変わるため、ユーティリティファイルから __dirname を単にエクスポートすることはできません。代わりに、import.meta.url を引数として受け取るヘルパー関数をエクスポートすることで、コードをクリーンに保つことができます。

Related Error Notes