Node.js の ESM で「__dirname is not defined」が解決できない
ES Modules では CommonJS の __dirname / __filename が定義されないためです。
import.meta.url から導出するか、Node 20.11 以降なら import.meta.dirname を使います。
#nodejs#esm#dirname#import-meta#modules
要約
ReferenceError: __dirname is not defined は、ファイルが ES Modules として実行され、CommonJS のグローバル __dirname / __filename が ESM には存在しないために起きます。import.meta.url から自前で算出するか、Node.js 20.11 以降なら import.meta.dirname を使えば解決します。
よくある原因
- ESM で実行されている:
package.jsonに"type": "module"がある、または拡張子が.mjsのため、CommonJS のグローバルが無い。 - __dirname は CJS 専用:
__dirname/__filename/requireは CommonJS ラッパーが注入する変数で、ESM スコープには注入されない。 - コピペ由来: CommonJS 前提のブログ記事のコードをそのまま ESM プロジェクトに持ち込んでいる。
解決策
1. import.meta.url から導出する(全バージョン対応)
import { fileURLToPath } from "node:url";
import { dirname } from "node:path";
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);この手法は Node.js の公式 ESM ドキュメントで案内されている定番です。
2. import.meta.dirname を使う(Node 20.11+ / 21.2+)
新しめの Node ならワンライナーで済みます。
const dir = import.meta.dirname; // __dirname 相当
const file = import.meta.filename; // __filename 相当3. パス結合に使う
import { join } from "node:path";
const configPath = join(import.meta.dirname, "config.json");import.meta.dirname は Node 20.11.0 / 21.2.0 で追加されたため、それ未満を含むサポート対象がある場合は解決策 1 を採用してください。