Node.jsでのアプリケーション開発において、現在実行されているスクリプトファイルのフルパスを取得する作業は非常に頻繁に発生します。
ログ出力でファイル名を記録したり、設定ファイルを相対パスではなく絶対パスで読み込んだりする際に、現在のファイル名を知ることは不可欠です。
Node.jsには古くから__filenameという便利なグローバル変数が用意されてきましたが、近年主流となっているESモジュール(ESM)環境ではその使い勝手が変わっています。
本記事では、従来のCommonJS環境での使い方から、最新のESモジュール環境における記述方法まで、実務で役立つ知識を詳しく解説します。
2026年現在のNode.js開発において、環境に合わせた最適なファイルパス取得方法をマスターしましょう。
CommonJSにおける__filenameの基本と仕組み
Node.jsの伝統的なモジュールシステムであるCommonJS(CJS)では、__filenameという変数が標準で提供されています。
この変数は、実行中のスクリプトファイルの絶対パスを格納している特別な変数です。
開発者が明示的に定義することなく、各モジュール内で自由に使用できるのが特徴です。
まずは、CommonJS環境での基本的な使用例を見てみましょう。
// CommonJS環境(拡張子が.jsまたは.cjsの場合)での例
// 現在のファイルの絶対パスを表示します
console.log("現在のファイルパス:", __filename);
// pathモジュールと組み合わせてファイル名だけを抽出する例
const path = require('path');
const fileName = path.basename(__filename);
console.log("ファイル名のみ:", fileName);
現在のファイルパス: /Users/username/project/src/app.js
ファイル名のみ: app.js
このように、__filenameを参照するだけで、そのコードが書かれているファイルのフルパスを簡単に取得できます。
Node.jsは各ファイルを読み込む際、関数でコードを包み込む「モジュールラッパー」という仕組みを利用しています。
__filenameや__dirname、require、module、exportsはこのラッパー関数の引数として渡されているため、グローバル変数の感覚で使用可能なのです。
CommonJSは依然として多くの既存プロジェクトで利用されているため、この基本動作を理解しておくことは重要です。
ESモジュール(ESM)で__filenameが使えない理由
Node.js v12以降、標準仕様であるESモジュール(ESM)のサポートが本格化しました。
しかし、ESモジュール環境では__filenameや__dirnameは定義されていません。
ESMはブラウザ環境との互換性を重視しており、Node.js固有のモジュールラッパーに依存しない設計になっているからです。
もしtype: "module"が設定されたプロジェクトや、拡張子が.mjsのファイル内で直接__filenameを呼び出すと、以下のようなエラーが発生します。
ReferenceError: __filename is not defined in ES module scope
このエラーは、多くの開発者がESM移行時に最初に直面する課題の一つです。
ESMではパス情報を取得するために、import.metaという新しいオブジェクトを使用します。
ESモジュールでのファイル名取得:最新の記述方法
2026年現在のモダンなNode.js開発では、ESMでのパス取得方法が標準化されています。
以前は少し複雑な手順が必要でしたが、現在のNode.jsではより簡潔な方法も提供されています。
import.meta.filenameを使用する(推奨)
Node.jsの比較的新しいバージョン(v20.11.0以降)では、ESM内でも直感的にパスを取得できるプロパティが追加されました。
それがimport.meta.filenameです。
これを利用すれば、CommonJSの__filenameと全く同じ感覚で絶対パスを取得できます。
// ESモジュール環境(拡張子が.mjsまたはpackage.jsonでtype: module指定時)
// import.meta.filename を使った取得
const currentFile = import.meta.filename;
console.log("ESMでのファイルパス:", currentFile);
ESMでのファイルパス: /Users/username/project/src/main.mjs
この方法は記述が非常にシンプルであり、2026年時点でのデファクトスタンダードとなっています。
特別なライブラリのインポートも不要なため、最新の実行環境を前提とするなら、この書き方がもっとも推奨されます。
import.meta.urlから変換する方法(従来の方法)
古い環境や、より汎用的なESMの仕組みを理解するためには、import.meta.urlを使用した方法も知っておくべきです。
import.meta.urlは、ファイルの場所をfile:///...形式のURL形式で返します。
これをファイルシステムのパス形式に変換するには、urlモジュールのfileURLToPath関数を使用します。
import { fileURLToPath } from 'url';
import path from 'path';
// 現在のファイルのURLを取得 (例: file:///path/to/file.js)
const __filename = fileURLToPath(import.meta.url);
// ファイル名だけを抽出する場合
const fileName = path.basename(__filename);
console.log("変換後のパス:", __filename);
console.log("ファイル名:", fileName);
なぜこの変換が必要かというと、WindowsとUNIX系OSではパスの区切り文字や形式が異なるからです。
fileURLToPathを通すことで、実行環境に合わせた正しいファイルパス形式が保証されます。
__filenameと__dirnameの使い分け
ファイルパスを扱う際、__filenameとセットで語られるのが__dirnameです。
これらの違いを明確に理解しておくことで、パス操作のミスを減らすことができます。
| 変数名 | 取得できる内容 | 主な用途 |
|---|---|---|
__filename | 実行中ファイルの絶対パス(ファイル名を含む) | ログ記録、特定のファイルそのものの操作 |
__dirname | 実行中ファイルが置かれているディレクトリの絶対パス | 同じディレクトリ内の別ファイルの読み込み |
ESMにおいても同様にimport.meta.dirnameが追加されており、現在のディレクトリパスを簡単に取得できます。
基本的には、ファイルそのものを指したい場合は__filename(またはimport.meta.filename)を使用します。
そのファイルと同じフォルダ内にある他のアセット(設定ファイルや画像など)を指したい場合は__dirnameを起点にするのが一般的です。
実務での活用例:パスを安全に結合する
取得したファイルパスをそのまま使うだけでなく、他のパスと結合して利用するケースが多くあります。
この時、文字列結合(+ や テンプレートリテラル)を使ってパスを作るのは避けるべきです。
OSごとの互換性を保つため、必ずpathモジュールを併用するようにしましょう。
import path from 'path';
// 現在のファイルパスを取得
const currentFile = import.meta.filename;
// 現在のファイルと同じ場所にある 'config.json' への絶対パスを作成
const configPath = path.join(path.dirname(currentFile), 'config.json');
console.log("設定ファイルのパス:", configPath);
path.joinやpath.resolveを使用する習慣をつけることで、Windows環境でスラッシュが逆向きになる等のトラブルを未然に防ぐことができます。
特にクラウド環境(Linuxベース)とローカル開発環境(Windows/macOS)で異なるOSを使用している場合に、この手法は絶大な効果を発揮します。
注意点:process.cwd()との違い
ファイル名を取得する際に混同しやすいのがprocess.cwd()です。
__filenameが「プログラムが書かれているファイル」を指すのに対し、process.cwd()は「コマンドを実行したカレントディレクトリ」を指します。
例えば、/Users/project/ディレクトリにいて、node src/app.jsを実行したとします。
この場合、__filenameは/Users/project/src/app.jsとなりますが、process.cwd()は/Users/project/となります。
実行場所によって結果が変わるprocess.cwd()に対し、__filenameはファイルが移動しない限り常に一定のパスを返します。
ライブラリやツールを作成する際は、この挙動の違いを考慮して、どちらのパスを使用すべきか慎重に選択してください。
まとめ
Node.jsにおける__filenameは、実行中のスクリプトファイルの絶対パスを特定するための極めて重要な要素です。
従来のCommonJS環境ではグローバル変数として手軽に利用できましたが、ESモジュール環境ではその扱いが変わったことを理解しておく必要があります。
最新のNode.js(2026年現在の環境)であれば、import.meta.filenameを使用するのがもっともシンプルで確実な方法です。
一方で、より広範な互換性が必要な場合は、fileURLToPath(import.meta.url)を用いた変換手法も有効です。
OSに依存しない堅牢なアプリケーションを構築するために、これらのパス取得方法とpathモジュールの活用を徹底しましょう。
適切なパス操作は、デバッグのしやすさやメンテナンス性の向上に直結する、バックエンド開発の基本スキルと言えます。
