← 記事一覧

JSON を最小化する方法 —— そしてやるべきとき

JSON の最小化はファイルサイズを減らし API 応答を速くするために不要な空白をすべて削除。JavaScript、Python、コマンドライン、ブラウザでの最小化方法 —— そして必要のないときを学ぶ。

JSON は設計上、空白に寛容です。JSON ビューティファイア は、コンパクトに機械生成された文字列をインデント付きで人間に読みやすい出力に展開します。JSON ミニファイア は正反対 —— 空白を全部削ぎ落としてファイルサイズを減らします。どちらの操作もデータ自体は完全に変えず、空白だけが変わります。本ガイドでは、いつ整形すべきか、いつ最小化すべきか、そしてその両方をどうやるか —— JavaScript、Python、コマンドライン、そしてブラウザの中で —— を扱います。

JSON を最小化するとは具体的に何をするか

整形済みの JSON オブジェクトを考えてみます:

{
  "user": {
    "id": 42,
    "name": "Alice",
    "roles": [
      "admin",
      "editor"
    ],
    "active": true
  }
}

最小化後:

{"user":{"id":42,"name":"Alice","roles":["admin","editor"],"active":true}}

2 つの文字列は意味的に同一です。すべての JSON パーサーは同じデータとして扱います。最小化版は 73 文字、整形版は 110 文字。34% の削減 —— JSON が大きく、ネストが深くなるほど差は広がります。

削られるもの: すべての改行、すべてのインデント用スペースとタブ、キーと値を分ける : の前後のスペース、項目を区切る , の後のスペース。

決して削られないもの: 文字列値の内側の空白("hello world" はそのまま "hello world")、そして実データ:キー、値、構造文字。

逆: JSON ビューティファイアとは

JSON ビューティファイア —— JSON フォーマッターや JSON プリティプリンターとも呼ばれます —— はミニファイアの逆を行います。コンパクトで読みにくい JSON を一貫したインデントと改行で展開し、人間の読み手に構造がすぐ伝わるようにします。

この文脈では「beautify」「format」「pretty-print」「indent」はすべて同じことを意味します。出力は入力と意味的に同一で、空白だけが変わります。

// ミニファイ済み(API やログから受け取るもの)
{"order":{"id":1001,"items":[{"sku":"A1","qty":2},{"sku":"B3","qty":1}],"total":49.99}}

// ビューティファイ後(2 スペースインデント)
{
  "order": {
    "id": 1001,
    "items": [
      { "sku": "A1", "qty": 2 },
      { "sku": "B3", "qty": 1 }
    ],
    "total": 49.99
  }
}

いつ JSON をビューティファイすべきか

最も一般的なのは最小化の逆のケースです: コンパクトな JSON を受け取った —— API レスポンス、ログファイル、データベースエクスポート、同僚からのメッセージ —— ので、読むか編集する必要がある場合です。

  • API レスポンスのデバッグ —— ミニファイ済みのレスポンスはほぼ目で追えない。整形に 1 秒、全キーが見える
  • 設定ファイルの編集 —— JSON 設定の変更をコミットする前に整形すれば、diff が読みやすくレビューも追える
  • データ構造のドキュメント化 —— README、wiki、PR 説明で整形された JSON は単一行よりはるかに構造を伝える
  • 未知のデータの確認 —— 新しい API や見たことのないデータセットでは、最初に整形すれば形がひと目でわかる
  • 壊れた JSON の修復 —— 整形は副作用として JSON を検証してくれる。出力が変だったりエラーが出ればその入力には文法問題がある

fixjson で JSON をビューティファイする方法

fixjson の JSON ビューティファイア は有効な JSON も壊れた JSON も扱えます —— ほとんどのフォーマッターには無理なことです。使い方:

  1. JSON を貼り付ける 左の入力パネルに。ミニファイ済み、部分的に整形、あるいは壊れていてもよい(末尾カンマ、シングルクオート、クオートなしキー —— すべて受け付け)。
  2. 出力が即座に表示 右側に、2 スペースインデントで整形されて。ボタンは不要 —— 入力に合わせて更新される。
  3. インデントを調整 必要なら。インデントセレクタで 2 スペース、4 スペース、タブを切り替えてプロジェクトのスタイルに合わせられる。
  4. 結果をコピー 出力パネルヘッダーのコピー ボタンか、全選択して貼り付け。

JSON にエラーがあれば、fixjson が整形前に自動で修復します —— 末尾カンマ削除、シングルクオートをダブルに、足りない括弧を閉じる。LLM、Python REPL、ログファイルからの生出力を貼っても、手動で 1 つずつ直さずにきれいに整形された JSON が返ってきます。

すべてはブラウザ内で動きます。データはどのサーバーにも送られません —— JSON に API キーやユーザーレコードなど機微情報が含まれるときに重要です。

コードで JSON を整形する

ブラウザツールではなくプログラムで整形済み JSON を作るときは、JSON.stringify の第 3 引数がインデントを制御します:

// 2 スペースインデント
JSON.stringify(data, null, 2);

// 4 スペースインデント
JSON.stringify(data, null, 4);

// タブインデント
JSON.stringify(data, null, '\t');

Python では:

import json

# 2 スペースインデント、キーをソート
print(json.dumps(data, indent=2, sort_keys=True))

コマンドラインで jq(デフォルト出力がすでに整形済み):

jq . data.min.json

JavaScript で JSON を最小化する方法

JavaScript 組み込みの JSON.stringify は第 3 引数(スペーサー)を省略すると JSON を最小化します。

JavaScript オブジェクトから

const data = {
  user: {
    id: 42,
    name: "Alice",
    roles: ["admin", "editor"],
    active: true
  }
};

const minified = JSON.stringify(data);
// {"user":{"id":42,"name":"Alice","roles":["admin","editor"],"active":true}}

ライブラリは不要です。JSON.stringify(value) は常にコンパクトな出力を生成します。

JSON 文字列から(parse して再 stringify)

整形済みの JSON 文字列から最小化したい場合:

const formatted = `{
  "user": {
    "id": 42,
    "name": "Alice"
  }
}`;

const minified = JSON.stringify(JSON.parse(formatted));
// {"user":{"id":42,"name":"Alice"}}

この往復 —— parse してからスペーサーなしで stringify —— が標準的な手法です。副作用として有用なのは、JSON.parse が無効な入力で例外を投げる点。送信前に壊れた JSON を捕まえられます。

Node.js でファイルから読み込む

import { readFileSync, writeFileSync } from 'fs';

const input = readFileSync('data.json', 'utf8');
const minified = JSON.stringify(JSON.parse(input));
writeFileSync('data.min.json', minified);

Python で JSON を最小化する方法

Python の json モジュールでは、json.dumps に 2 つの引数を渡すことできれいに処理できます。

Python dict から

import json

data = {
    "user": {
        "id": 42,
        "name": "Alice",
        "roles": ["admin", "editor"],
        "active": True
    }
}

minified = json.dumps(data, separators=(',', ':'))
# {"user":{"id":42,"name":"Alice","roles":["admin","editor"],"active":true}}

鍵となるのは separators=(',', ':') 引数。デフォルトでは json.dumps', '': '(末尾スペースつき)を使います。(',', ':') を渡すとそれらのスペースを完全に削除します。

JSON ファイルから

import json

with open('data.json', 'r') as f:
    data = json.load(f)

with open('data.min.json', 'w') as f:
    json.dump(data, f, separators=(',', ':'))

コマンドラインで JSON を最小化する方法

jq を使う

jq は Unix 系システムでの定番 JSON プロセッサです。-c フラグでコンパクト(最小化)出力になります:

jq -c . data.json > data.min.json

# インライン
echo '{ "name": "Alice", "age": 30 }' | jq -c .
# {"name":"Alice","age":30}

Python を使う(追加インストール不要)

jq が無くても Python はほぼ常にあります:

python3 -m json.tool --compact data.json > data.min.json

--compact フラグは Python 3.9 で追加されました。古いバージョンでは:

python3 -c "import json,sys; print(json.dumps(json.load(sys.stdin), separators=(',',':')))" < data.json

オンラインで JSON を最小化する方法

ワンショットの作業 —— コミット前の設定ファイル、どこかにコピーする API レスポンス —— にはブラウザ型のツールがどんな CLI セットアップより速いです。良いオンライン JSON ミニファイアは、貼り付けやファイルアップロードを受け付け、クライアント側で即座に最小化し、データをサーバーに送らないものです。

fixjson の JSON ミニファイア はすべての処理をローカルで行います。JSON を貼り、Minify をクリックして結果をコピー —— 何もブラウザの外に出ません。

JSON の最小化で実際にどれだけ節約できるか

削減幅は元の整形のされ方によります。

  • 軽く整形済み(2 スペースインデント、浅いネスト): 典型的に 15–25% 削減
  • 重く整形済み(4 スペースインデント、深いネスト、キー多): 典型的に 30–50% 削減
  • すでにコンパクト(最小化済みまたは機械生成): 削減はほぼ 0%

実例 —— 100 件のユーザーオブジェクトを返す REST API レスポンス:

形式サイズ
整形済み(2 スペース)24.8 KB
最小化16.1 KB
最小化 + gzip3.2 KB

gzip の行に注目。本ガイドで最も重要な観察であり、次の問いに直結します。

最小化と圧縮の違いは?

最小化は空白文字を削るだけ —— データレベルでロスレス、より小さなテキスト文字列を生みます。圧縮(gzip、Brotli、zstd)はファイル全体で繰り返しのバイトパターンを見つけ、より効率的に表現するアルゴリズムを使います。バイナリレベルで動き、解凍しないと読めない出力になります。

実用上の含意: サーバーで HTTP 圧縮が有効なら —— あらゆる JSON API では有効であるべきですが —— gzip や Brotli は空白も他のあらゆるものと同じくらい強力に圧縮します。圧縮前に最小化しても、すでに圧縮が達成しているもの の上にわずかな追加(3〜8%)しか得られないのが普通です。

意思決定は次のように整理できます:

  • サーバーが HTTP 圧縮を使うなら: 最小化はマイナーな最適化
  • 圧縮なしでディスクや DB に JSON を保存しているなら: 最小化はストレージコストに有意な影響
  • HTTP 圧縮をサポートしないクライアントに送るなら: 最小化はより重要

実践での圧縮: HTTP/2、HTTP/3、確認ポイント

新しい HTTP バージョンでも計算は変わりません —— 圧縮は依然としてレスポンスボディレベルで起こります —— が、最小化するかを決めるときに見るべきヘッダがいくつかあります:

  • Content-Encoding: gzip(または Brotli の br、構成によっては zstd)—— 転送中のボディが圧縮されていることの確認。
  • Vary: Accept-Encoding —— CDN が圧縮レスポンスと非圧縮レスポンスを別々にキャッシュするために必要。
  • HTTP/2 / HTTP/3 のヘッダ圧縮(HPACK / QPACK) —— ヘッダ を圧縮するもので、ボディではない。JSON ペイロードの gzip/brotli の代替にはならない。

CDN がすでに br で配信しているなら、最小化で稼げるのは数パーセントの追加です。圧縮しないサービス(独自バイナリ、webhook の宛先、IoT エンドポイント)を運用しているなら、最小化は依然有用です。

大きな JSON は最小化よりもストリーミング

本当に大きなペイロード —— マルチ MB の API レスポンス、ログダンプ、データセットのエクスポート —— では、ひと塊を最小化するよりもストリーム するのが正攻法です。2 つのパターン:

  • NDJSON / JSON Lines —— 1 行 1 つの JSON 値を出力。クライアントは全文書を待たず、到着した行ごとにパースして処理できる。
  • チャンクのストリーミングパーサー —— clarinet / jsonparse のようなライブラリは、ワイヤから届くトークンを順次処理。メモリ制約のある環境で求められる挙動。

JSON を最小化すべきタイミング

本番 API レスポンス(HTTP 圧縮なし)

API サーバーが Content-Encoding: gzipContent-Encoding: br を有効にしていないと、空白の 1 バイトまで送られます。最小化はペイロードを小さくし、特に遅いモバイル回線でレスポンスを速くします。

HTML に埋め込んだ JSON

<script type="application/json"> タグや HTML 内に直接書かれた JSON はページ全体の重さの一部です。最小化すれば初期ページの軽さに貢献します。

大規模に保存される JSON ファイル

データウェアハウス、オブジェクトストレージ、データベースに数百万件の JSON を保存していて、ストレージ層で圧縮されていないなら、空白は積もります。1,000 万件で 30% 削減は意味あるレベルです。

サイズ上限のあるエッジケース

システムには厳しいサイズ上限があるものがあります: webhook ペイロード、特定のメッセージキュー、Cookie 値、URL パラメータ。JSON が上限に近いなら、最小化が最も簡単な対処法でしょう。

ビルド成果物とバンドル設定

フロントエンドのビルドにバンドルされる JSON 設定はバンドルサイズに寄与します。JS/CSS 同様、ビルド時に最小化するのが標準です。

やる必要がおそらくないとき

サーバーがすでに HTTP 圧縮している

レスポンスヘッダを確認。Content-Encoding: gzipContent-Encoding: br が見えるなら、転送中にすでに JSON が圧縮されています。その上に最小化を重ねても、すでに圧縮済みのペイロードでは数パーセントしか得られず、複雑性に見合わないことが多いです。

JSON が人間の閲覧用

開発者が編集する設定、デバッグログ、人手で確認するエクスポート —— これらは読みやすさが第一。人が定期的に読む JSON は最小化しないでください。

データがそもそも小さい

1 KB 未満の JSON では、最小化と整形の絶対差は 300 バイト未満になりがちです。この規模では HTTP リクエスト自体のオーバーヘッドが支配的で、本文で 200 バイト削っても計測可能な性能差は出ません。

デバッグを難しくする

ログ、エラー、監視に出る最小化済み JSON は目で追いづらい。本番で JSON を読むなら整形を維持しましょう。

ビルドパイプラインでの最小化

Node.js ビルドで JSON 設定を最小化する実用的な構成:

// scripts/minify-configs.js
import { readdirSync, readFileSync, writeFileSync } from 'fs';
import { join } from 'path';

const configDir = './config';
const outputDir = './dist/config';

for (const file of readdirSync(configDir)) {
  if (!file.endsWith('.json')) continue;
  const raw = readFileSync(join(configDir, file), 'utf8');
  const minified = JSON.stringify(JSON.parse(raw));
  writeFileSync(join(outputDir, file), minified);
  const saved = raw.length - minified.length;
  console.log(`${file}: ${raw.length} → ${minified.length} bytes (saved ${saved})`);
}

これをデプロイ前のステップとして実行。設定ファイルに不正な JSON があれば JSON.parse が例外を投げてビルドが落ちる —— まさに望むところ。

JSON 最小化でよくあるミス

難読化と勘違い

最小化された JSON は意味のある意味で隠されていません。フォーマッター に通せば誰でも数秒で読めます。機微データを最小化して仕事完了とみなさず、適切な暗号化を使うか、そもそも送らないことを検討してください。

Python のエンコーディングオプションを忘れる

json.dumps はデフォルトで ASCII 安全な出力に、非 ASCII 文字を \uXXXX にエスケープします。UTF-8 を保持するには ensure_ascii=False を渡してください:

minified = json.dumps(data, separators=(',', ':'), ensure_ascii=False)

大きな整数で精度が落ちる

大きな整数を含む JSON のパース→再 stringify は、言語によっては精度を失います。JavaScript の JSON.parse はすべての数値を IEEE 754 倍精度に変換するため、2⁵³ を超える整数は正確に表現できません。データベース ID や外部サービス ID のような大きな整数を含むなら、parse-stringify の往復で壊れないか確認してください。

よくある質問

JavaScript で JSON を最小化するには?

JSON.stringify(value) を第 3 引数なしで呼ぶ —— 出力は常にコンパクト。既存の文字列を最小化するには往復: JSON.stringify(JSON.parse(formatted))

JSON の最小化でファイルサイズは大きく減る?

圧縮前で通常 15〜50%、インデントとネストによる。ただしサーバーがすでに Content-Encoding: gzipbr を送るなら、gzip は空白も圧縮するので、先に最小化しても数パーセントしか上乗せされません。

JSON の最小化と圧縮の違いは?

最小化は空白を取り除いて人間可読のテキストのまま。圧縮(gzip、Brotli)はバイトを再エンコードし、読むには解凍が必要。両者は重ねられるが、転送中の作業の大半は圧縮が担う。

最小化と整形はどう違う?

対になる操作: 最小化は空白を削ってサイズを縮め、整形は空白を加えて読みやすくする。逆方向は JSON のフォーマット方法 を参照。

結論

JSON の最小化はもっともシンプルな最適化の 1 つです —— どの言語でも関数 1 つ、どのブラウザツールでも 1 クリック。やるべきタイミングは、HTTP 圧縮なしで JSON を転送する、ストレージ層で圧縮しないまま大規模に保存する、ビルド成果物に同梱するときです。

やってはいけないタイミングは、JSON が人間に読まれることが前提のとき、ペイロードがそもそも小さいとき、インフラがすでに転送時に圧縮しているときです。

本当に最小化が必要なときは —— ビルドスクリプトでも、CI ステップでも、ワンショットの掃除でも —— どの言語でも同じ手順: JSON をパースして、スペーサーなしでシリアライズする。パースを妨げるエラーがあれば、まず修復してから最小化してください。