Node.js環境において、JSONファイルを読み込む操作は、設定ファイルの取得やデータの永続化など、開発のあらゆる場面で頻繁に発生する基本的なタスクです。

長年にわたり、Node.jsではCommonJS形式の「require」を使用したシンプルな読み込みが一般的でしたが、近年のESモジュール(ESM)の普及やセキュリティ意識の高まりにより、その手法は多様化しています。

2026年現在のモダンな開発環境では、プロジェクトの構成や実行速度、メモリ効率に応じて、最適な読み込み手法を選択することが求められます。

本記事では、伝統的なfsモジュールによる処理から、最新のESM仕様に基づいたインポート属性(Import Attributes)まで、現場で役立つ具体的な実装方法を詳しく解説します。

1. Node.jsにおけるJSON読み込みの基本手法

Node.jsでJSONファイルを読み込む方法は、大きく分けて「同期的な読み込み」と「非同期的な読み込み」の2種類に分類されます。

同期的な読み込みはコードがシンプルになりますが、ファイル読み込み中にメインスレッドをブロックするため、サーバーアプリケーションでは注意が必要です。

一方で、非同期的な読み込みはNode.jsのノンブロッキングI/Oの特性を活かせるため、高パフォーマンスなアプリケーションに向いています。

また、モジュールシステムの違い(CommonJSかESMか)によって利用できる構文が異なる点も重要なポイントです。

2. CommonJSにおける伝統的なrequireによる読み込み

CommonJS(CJS)形式を採用している従来のプロジェクトでは、require関数を使用して簡単にJSONファイルを読み込むことが可能です。

この手法の最大のメリットは、拡張子を指定するだけでNode.jsが自動的にファイルをパースし、JavaScriptオブジェクトとして返してくれる点にあります。

JavaScript
// config.jsonの内容
// { "appName": "NodeApp", "version": "1.0.0" }

const config = require('./config.json');
console.log(config.appName);
実行結果
NodeApp

requireを使用する際の注意点

非常に便利なrequireですが、いくつかの重要な仕様を理解しておく必要があります。

まず、requireで読み込まれたJSONは内部的にキャッシュされるという性質があります。

同じプロセス内でファイルを書き換えたとしても、再度requireを呼び出すと古いデータが返されるため、動的に更新されるデータの読み込みには適していません。

また、読み込みが「同期的」に行われるため、巨大なJSONファイルを読み込む際にはアプリケーション全体のパフォーマンスが一時的に低下する恐れがあります。

3. fsモジュールを使用した柔軟な読み込み方法

より制御の効いた、あるいは最新の環境でも汎用的に使える方法が、Node.js標準のfs(File System)モジュールを利用する手法です。

この方法では、ファイルをバイナリまたは文字列として読み込み、手動でJSON.parse()を適用します。

fs.readFileSyncによる同期読み込み

スクリプトの初期化段階など、実行順序を保証したい場合には同期版のメソッドが利用されます。

JavaScript
const fs = require('fs');
const path = require('path');

// ファイルパスを絶対パスで指定
const filePath = path.join(__dirname, 'data.json');
const rawData = fs.readFileSync(filePath, 'utf8');
const jsonData = JSON.parse(rawData);

console.log(jsonData);

fs.promisesによる非同期読み込み(推奨)

現代のNode.js開発において、最も推奨されるのが「fs/promises」を利用した非同期処理です。

async/await構文と組み合わせることで、可読性を維持しつつ非同期処理を実現できます。

JavaScript
const fs = require('fs').promises;
const path = require('path');

async function loadConfig() {
  try {
    const filePath = path.join(__dirname, 'config.json');
    const data = await fs.readFile(filePath, 'utf8');
    return JSON.parse(data);
  } catch (error) {
    console.error('ファイルの読み込みに失敗しました:', error);
  }
}

loadConfig().then(config => console.log(config));

4. モダンなESモジュール(ESM)でのJSON読み込み

近年のNode.jsでは、拡張子が.mjsのファイルや、package.json"type": "module"が指定されたプロジェクトが主流となっています。

ESM環境ではrequireが使用できないため、従来とは異なるアプローチが必要になります。

Import Attributes(旧Import Assertions)の利用

2026年現在、Node.jsの最新安定版では、import文で直接JSONを読み込む「Import Attributes」がサポートされています。

この機能により、静的な解析が可能な安全な方法でJSONをインポートできるようになります。

JavaScript
// ESモジュール内での記述
import config from './config.json' with { type: 'json' };

console.log(config.version);

以前はassert { type: 'json' }という構文でしたが、現在はwith { type: 'json' }が標準的な仕様となっています。

この方法で読み込まれたJSONは、requireと同様に読み込み時にパースされ、デフォルトエクスポートとして扱われます。

ESM環境での動的な読み込み

実行時にパスが決まるファイルをESM環境で読み込む場合は、fs.promisesimport.meta.urlを組み合わせます。

ESMでは__dirnameが使用できないため、URL形式のパスをファイルパスに変換する手間が必要です。

JavaScript
import { readFile } from 'fs/promises';
import { fileURLToPath } from 'url';
import { dirname, join } from 'path';

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

const loadDynamicJSON = async (fileName) => {
  const path = join(__dirname, fileName);
  const content = await readFile(path, 'utf8');
  return JSON.parse(content);
};

const data = await loadDynamicJSON('data.json');
console.log(data);

5. 実行環境と用途に応じた手法の比較

適切な手法を選択するために、それぞれの特徴を表にまとめました。

手法モジュール形式同期/非同期主な特徴・メリット
require()CommonJS同期簡潔だがキャッシュされる。動的更新に弱い。
fs.readFileSync共通同期シンプルだが処理をブロックする。初期化時に適向。
fs.promises.readFile共通非同期最も安全で高速。async/awaitが利用可能。
import ... withESM同期(静的)最新仕様。標準的な記述でセキュリティも高い。

6. 実践的なエラーハンドリングとバリデーション

JSONの読み込みには、常に「ファイルが存在しない」「JSONの形式が壊れている」といったリスクが伴います。

堅牢なアプリケーションを作成するためには、適切なエラーハンドリングが欠かせません。

JSON.parseの例外処理

JSON.parse()は、不正な形式の文字列が渡されると例外をスローします。

必ずtry...catchブロックで囲み、異常終了を防ぐようにしましょう。

JavaScript
function safeParse(text) {
  try {
    return JSON.parse(text);
  } catch (e) {
    console.error('JSONの解析に失敗しました。フォーマットを確認してください。');
    return null;
  }
}

ファイルの存在確認

ファイルを読み込む前に、fs.accessなどを使用して存在を確認することも有効ですが、読み込み処理の中でエラーをキャッチする方が効率的な場合が多いです。

Node.jsでは、存在しないファイルを読み込もうとすると、エラーコード'ENOENT'が発生します。

7. 大規模なJSONファイルを扱う場合の最適化

ファイルサイズが数MBから数百MBに及ぶ巨大なJSONを扱う場合、fs.readFileJSON.parseを使用すると、一度に全てのデータをメモリに読み込むためメモリ不足(OOM)に陥る可能性があります。

大規模データを扱う場合は「ストリーム」の利用を検討してください

Node.jsのfs.createReadStreamと、stream-jsonのようなライブラリを組み合わせることで、データを分割して少しずつ処理することが可能です。

これにより、メモリ消費量を一定に抑えつつ、効率的にデータを加工できます。

8. まとめ

Node.jsにおけるJSONファイルの読み込みは、シンプルなようで奥が深いトピックです。

2026年現在の開発においては、CommonJSならrequire、ESMならimport ... with属性を使用するのが最も手軽な方法です。

しかし、柔軟性やパフォーマンスを重視するならば、fs/promisesを用いた非同期読み込みが最良の選択肢となります。

また、ファイルのパス解決にはpathモジュールを適切に使用し、予期せぬエラーを防ぐために必ずエラーハンドリングを実装してください。

プロジェクトの要件や将来の拡張性を考慮し、今回紹介した手法の中から最適なものを選んでみてください。