なぜ JSON はコメントを禁止したのか — Crockford の主張と JSON5・JSONC・HJSON が生まれた理由

約9分

JSON にはコメント構文がありません。これは「忘れた」のでも「単に古いから」でもなく、設計者の Douglas Crockford が意図的に外した選択です。本記事では、その判断の背景・実際の論拠・派生形式(JSON5・JSONC・HJSON)が生まれた理由・そして「設定ファイルに JSON を使うべきか」という現代的な問いを整理します。

仕様の確認

ECMA-404RFC 8259 の双方で、JSON のトークンとして許される文字は厳格に定義されており、コメント構文 // /* */ は構文エラーです。

{
	// これは JSON では許可されない
	"name": "Alice"
}

実際にこの JSON を JSON.parse() に通すと、Unexpected token / のような例外が出ます。仕様準拠のパーサはコメントを受け付けません。

Crockford の意図

Douglas Crockford は 2012 年の Google+ 投稿で、コメントを外した理由を説明しています(投稿は閉鎖されたが、複数の二次資料に引用が残っている)。要約すると:

JSON にはコメントを許そうかと思った時期があった。やめた理由は、人々が parse 指示子を埋め込み始めて、相互運用性を壊すと予想したからだ。

コメント機能が必要なら、JSON に通す前に剥がすミニファイヤーを書くのは簡単だ。

つまり Crockford の懸念は単なる美学ではなく、「コメントを許すと、コメントの中にディレクティブを書く悪習が生まれ、JSON の単純さが壊れる」という実装観点での予測でした。XML の processing instruction (<?xml-stylesheet ?>) や、HTML のコメント内 conditional comment(IE 専用)の前例があり、それを避けたい意図です。

「設定ファイルでコメント書きたい」問題

JSON はもともと JavaScript からデータを取り出す ための小さな表現でしたが、軽量さゆえに設定ファイル形式として広く使われてしまいました。設定ファイルは「なぜこの値か」を残したいので、コメント不在は痛点になります。

この摩擦が、複数の JSON 派生形式を生みました。

JSON5:人間に書きやすい superset

JSON5 は 2012 年〜の派生で、JSON をECMAScript 5 由来の構文に拡張したもの。

{
	// コメント可
	name: 'Alice', // クォートのキー名OK
	skills: ['JavaScript', 'Python'], // 末尾カンマOK
	hex: 0xff, // 16進数OK
	multiline: 'a b' // 行継続OK
}
  • 単行・複数行コメント
  • キー名のクォート省略
  • シングルクォート文字列
  • 末尾カンマ
  • 16 進数リテラル

設定ファイル用の JSON」として、Babel・ESLint・Stylelint など多くのツールが JSON5 を採用しました。

ただし JSON5 は「JSON のスーパーセット」であって、JSON の標準パーサでは読めません。JSON5 ファイルを共有するには JSON5 専用パーサが必要。

JSONC(JSON with Comments):Microsoft の中間案

VS Code が tsconfig.json などで使い始めたのが JSONC

  • // /* */ のコメント許可
  • 末尾カンマ許可
  • それ以外は標準 JSON

JSON5 ほど多くの拡張は持たず、「コメントと末尾カンマだけ追加」というミニマルな立場。tsconfig.json.vscode/settings.json.eslintrc.json などで使われています。

問題は、ファイルの拡張子は .json のままなので、標準 JSON パーサが食わせられたら例外を投げる点です。「JSON5 ではないが JSON でもない」中間状態。

HJSON:人間が書く前提の “Human JSON”

HJSON はさらに踏み込んで、クォートを完全に省略可能にした派生形式。

{
  name: Alice
  skills: [
    JavaScript
    Python
  ]
  bio:
    '''
    複数行の文字列も
    そのまま書ける
    '''
}
  • カンマ不要
  • 文字列のクォート省略
  • 三重シングルクォートで複数行リテラル

YAML に近い人間寄りの書き味ですが、YAML ほど普及はしていません。

なぜ YAML を使わなかったのか

「コメントが要る・人間が書く設定ファイル」なら YAML を使えば良いように見えます。実際、Kubernetes や CI/CD(GitHub Actions、GitLab CI)は YAML を選択しました。一方で Babel や TypeScript が JSON 派生(babel.config.json / tsconfig.json)を選んだのには理由があります:

  • JSON のスコープが小さいので、ツールの実装が単純
  • YAML のNorway ProblemNOfalse に解釈される)など、型推論の罠を持ち込みたくない
  • フロントエンドツールチェーンは Node.js でできており、JSON のパーサが標準ライブラリで来ている

つまり「コメントは欲しいが YAML の複雑さは要らない」というニッチに、JSON5 / JSONC が滑り込んだ形です。

設定ファイル形式の系譜(簡易版)

形式コメント末尾カンマクォート省略採用例
JSONAPI レスポンス、package.json
JSONCtsconfig.json、VS Code 設定
JSON5キーのみ ✓Babel、ESLint
HJSON一部の Go ツール
YAMLKubernetes、GitHub Actions
TOMLCargo、pyproject.toml

現代の評価:Crockford は正しかったか

20 年経った今、コメント禁止という判断が適切だったかを整理すると:

  • API のデータ交換形式としては正解:パーサの実装が単純で、相互運用性が極めて高い。fetch().then(r => r.json()) が世界中どこでも動く理由
  • 設定ファイル用途では限界が露呈:JSONC / JSON5 のような派生が乱立し、「.json という拡張子なのに標準パーサで読めない」状態が常態化

設計判断の根拠(ディレクティブの埋め込みを防ぐ)は妥当だったが、設定ファイルに使われる前提を想定できなかった部分はある。Crockford 自身も後年「JSON は設定ファイルには向いていない、TOML や YAML を使え」と発言しています。

実装上の含意

新規プロジェクトで設定ファイル形式を選ぶときの目安:

  • データ交換用 → JSON 一択(互換性最優先)
  • TS / Node の開発設定 → JSONC(既存ツール群がそうなっている)
  • Babel / ESLint 系 → JSON5
  • デプロイ・インフラ系 → YAML(ただし Norway Problem / 型推論の癖を意識)
  • 新規ツールの設定形式を自分で選べるなら → TOML(曖昧さが少ない、コメントあり、型が明示的)
# 新規ツールの設定例
[server]
host = "0.0.0.0"
port = 8080  # 整数

まとめ

JSON のコメント禁止は、ディレクティブ埋め込みによる方言乱立を予防するための意図的な設計判断でした。データ交換形式としては成功したものの、設定ファイル用途で広く使われた結果として、JSONC・JSON5・HJSON といった非互換派生を生み出すことになります。「拡張子は同じ .json だが、ツールごとにコメント許容が違う」という現代の混乱の出発点でもあり、設計判断のトレードオフを観察する好例です。

実際の JSON ファイルの整形・検証は JSON フォーマッター で確認できます。