JSON 工具箱

JSON、TOML、YAML、CSON:配置檔案格式怎麼選

結論:配置檔案需要註釋、日期與多行文字,這些恰好是 JSON 的短板。本文把 JSON、TOML、YAML、CSON 放進同一張表比較語法與工具支援,給出按情境的選型結論,並說明轉換時哪些資訊一定會遺失。

入門約 9 分鐘發佈於 2026-10-31更新於 2026-10-31
JSON、TOML、YAML 與 CSON 配置檔案格式對比封面

結論:機器交換一律用 JSON,人手維護的配置按生態選 TOML 或 YAML(Kubernetes、CI 鎖 YAML,結構扁平或要原生日期選 TOML);只有拿不準讀取方是否支援方言時,才退回 JSONC。

JSON 是給機器交換資料用的,配置檔案是給人寫給人看的。把這兩件事混為一談,就會得到一份既不能寫註釋、又不敢刪欄位的 config.json。

一、先分清兩類檔案

資料交換格式和配置格式的目標並不相同,只是經常被同一個人寫在同一台機器上。

維度 資料交換 配置檔案
誰寫 程式序列化 人手寫或半手工維護
誰讀 對方的程式 自家程式
關心什麼 零歧義、體積、解析速度 可讀性、可註釋、可 diff
變更頻率 每次請求 偶爾,且要審查
出錯代價 介面 500 服務起不來

JSON 在左列幾乎滿分:語法極簡、所有語言都有解析器、沒有註釋也就沒有「註釋與值不一致」的問題。但它的嚴格性在右列全是負擔:不能寫註釋、不能寫尾逗號、不能寫日期、多行文字必須壓成一行加 \n。

二、四位選手與語法能力

  • JSON:RFC 8259 與 ECMA-404 定義,只有物件、陣列、字串、數字、布林、null 六種值。它是資料交換的事實標準,也是唯一一個「不用選、預設就用它」的格式。
  • TOML:Tom Preston-Werner 發起,v1.0.0 於 2021 年 1 月發布。定位很明確——「語意顯而易見、能無歧義映射到雜湊表」的最小配置格式。Cargo.toml、pyproject.toml 都以它為預設。
  • YAML:1.2.2 是目前規範。縮排表達層級,支援註釋、錨點、多文件。Kubernetes 清單、GitHub Actions、Ansible 都離不開它,代價是規範龐大、實作差異多。
  • CSON:CoffeeScript Object Notation,用 CoffeeScript 的物件字面量語法寫配置,Atom 編輯器的 config.cson 就是它。註釋、無引號鍵名、尾逗號都支援,但生態基本停留在 JavaScript 圈。

2.1 語法能力對照表

能力 JSON TOML YAML CSON
註釋 ✗ ✓ # ✓ # ✓ #
尾逗號 ✗ ✓(陣列、內聯表) ✓(串流集合) ✓
鍵名可省略引號 ✗ ✓ ✓ ✓
原生日期時間 ✗(只能字串) ✓ 四種日期時間型別 ✓(1.1 自動解析) ✗
多行字串 ✗(\n 轉義) ✓ """ 與 ''' ✓ 區塊純量與折疊純量 ✓ heredoc
整數範圍 規範不限,互通按雙精度 64 位有號,必須無損 任意精度 + .inf/.nan 跟隨 JavaScript
巢狀表達 大括號與方括號 表、陣列表、點號鍵 縮排 縮排
縮排敏感 ✗ ✗ ✓ ✓
null ✓ ✗ ✓ ✓
工具覆蓋 全部語言 主流語言 全部語言,實作有差異 僅 JavaScript 生態

這張表裡有兩格值得單獨說:TOML 沒有 null,這是從 JSON 轉過去時最常見的失敗點;YAML 的「原生日期」在 1.1 解析器裡會自動把 2026-10-31 變成日期物件,跨語言傳輸時型別會漂移。

三、註釋:JSON 唯一繞不過去的短板

先給結論:如果這份檔案由人維護、需要解釋「為什麼是這個值」,就不該用標準 JSON。

現成的四條路,按侵入性從低到高:

  1. 換成 JSONC。標準 JSON 加註釋與尾逗號,VS Code 的 settings.json、tsconfig.json 都是它。代價是讀取方必須用 jsonc-parser 一類帶註釋能力的解析器,用 JSON.parse 直接讀會失敗。細節見 JSON5 與 JSONC:帶註釋的 JSON。
  2. 寫旁註檔案。config.json 保持機器可讀,config.md 寫清楚每個欄位的含義與取值理由,兩者在同一個目錄、同一次提交裡更新。
  3. 把說明塞進 Schema。JSON Schema 的 description、$comment 關鍵字可以承載欄位說明,但 Schema 通常不隨執行時配置一起下發,讀配置的人未必看得到。
  4. 換成 TOML 或 YAML。把註釋能力交給格式本身,解析器天然支援。
{
  // 固定 8080:前端建置腳本會讀取這個連接埠做代理
  "port": 8080,
  // 關閉熱更新,避免 CI 上檔案監聽耗盡 inode
  "watch": false
}

JSONC 的問題在於它仍是「方言」:檔案副檔名還是 .json,但只有部分工具認。對外傳輸、跨團隊交付時,它和標準 JSON 的邊界必須寫進文件。

四、日期與多行字串:TOML 的主場

TOML 把日期時間提升為一等型別,分四種:帶偏移的日期時間、本地日期時間、本地日期、本地時間。多行字串也有專門的語法,換行原樣保留:

title = "json-toolkit"
created = 2026-10-31T09:00:00+08:00
description = """
面向開發者的 JSON 工具集,
所有處理都在瀏覽器本地完成。
"""

同樣的資訊寫成 JSON,日期只能退化成字串,多行文字必須轉義:

{
  "title": "json-toolkit",
  "created": "2026-10-31T09:00:00+08:00",
  "description": "面向開發者的 JSON 工具集,\n所有處理都在瀏覽器本地完成。"
}

JSON 裡 "created" 只是一個長得像日期的字串,型別資訊由欄位契約承擔:雙方得額外約定「這個欄位一律 RFC 3339」。TOML 則由解析器直接給出日期物件,不需要口頭約定。

YAML 也能寫多行文字,但兩種寫法語意不同:| 保留換行,> 折疊成空格。選錯符號,一段地址或 SQL 就會在解析後變成一行,這種錯誤很難在審查裡看出來。

五、數字:最容易被忽略的差異

JSON 規範沒有數值精度限制,但 RFC 8259 同時提醒:跨實作交換時按 IEEE 754 雙精度處理才安全。JavaScript 裡超過 2^53 - 1 的整數會靜默丟精度:

JSON.parse('{"id":9007199254740993}').id
// 9007199254740992,最後一位被吃掉

TOML 明確要求 64 位有號整數必須無損處理,超出範圍要報錯而不是悄悄截斷;浮點按 binary64,另外支援 inf 與 nan。YAML 1.1 還多一個歷史包袱:1:30 會被解析成 90(六十進位),布林值接受 yes、no、on、off,於是經典的「挪威問題」——國家代碼 NO 變成 false。

處理金額時,無論用哪種格式,都不要依賴浮點數:用整數分、字串,或資料庫的 decimal 型別。格式化與精度問題在 JSON 與 YAML、XML 的互轉邊界 裡有更完整的討論。

六、表結構與巢狀:TOML 的邊界很清楚

TOML 用表表達巢狀,用雙中括號表達陣列表:

[server]
port = 8080

[[routes]]
path = "/parse"
method = "POST"

[[routes]]
path = "/minify"
method = "POST"

它有兩個硬邊界,轉換前必須知道:

  • TOML 文件的根是一個表,所以頂層是陣列的 JSON(如 [1, 2, 3])沒有合法的 TOML 表示,只能包一層 {"items": [...]};
  • TOML 沒有 null,JSON 裡的 null 欄位要嘛刪除、要嘛換成空字串或哨兵值,語意由呼叫方承擔。

YAML 則相反,巢狀深度不受限制,還能用錨點和合併鍵重複使用片段:

defaults: &defaults
  retries: 3
  timeoutMs: 5000

server:
  <<: *defaults
  port: 8080

錨點是 YAML 的獨有能力,也是轉換時的損失點:JSON 沒有引用語法,展開後檔案會變長,且再也認不出「這兩段本來是同一條配置」。

七、按情境選型的結論

情境 推薦 理由
對外 API、訊息佇列、快取 JSON 通用性最高,沒有任何協商成本
應用配置,結構扁平、型別明確 TOML 有註釋、有日期、整數無損,解析器行為穩定
Kubernetes、CI、Ansible YAML 生態鎖定,換格式等於換工具鏈
VS Code、tsconfig.json JSONC 工具原生支援,不需引入新格式
需要重複使用配置片段 YAML 錨點與合併鍵是唯一現成方案
程式生成、只被程式讀 JSON(壓縮) 無需註釋,體積與解析都最優
歷史 Atom / CoffeeScript 專案 CSON,但建議遷移 生態已邊緣化,遷移成本隨年限上升

一條經驗:配置檔案跟著生態走,不要跟著個人偏好走。 用 Rust 就寫 Cargo.toml,部署到 Kubernetes 就寫 YAML,做 VS Code 擴充套件就寫 JSONC;只有在沒有生態約束的新專案裡,才值得討論「哪種更好寫」。

八、轉換邊界:轉過去往往回不來

轉換方向 一定遺失的資訊 建議
JSON → TOML null、頂層陣列、無法表達的鍵名 先規整結構,剔除空欄位
TOML → JSON 註釋、日期型別、inf / nan 日期統一轉 RFC 3339 字串
YAML → JSON 註釋、錨點與合併鍵、標籤、多文件 先展開錨點,再逐文件轉換
JSON → YAML 無結構性損失,但日期字串可能被自動解析 給日期字串加引號
CSON → JSON 註釋、CoffeeScript 表達式 只做一次性遷移,不雙向同步

轉換工具能保證「值對」,但保證不了「註釋還在」。所以不要設計「JSON 是原始檔、YAML 是建置產物」這種雙向流程;要嘛單向生成,要嘛只維護一份原始檔。

九、實作清單

  • [ ] 團隊文件裡寫明「哪類檔案用哪種格式」,並列出允許的方言;
  • [ ] 人寫的配置優先 TOML 或 YAML,機器交換一律 JSON;
  • [ ] 日期欄位在 JSON 裡統一用 RFC 3339 字串,並在 Schema 裡標註格式;
  • [ ] 金額與超過 2^53 的整數用字串或整數分,不依賴浮點;
  • [ ] CI 裡對每種格式分別校驗,不要用 JSON.parse 校驗 YAML;
  • [ ] 格式遷移只做單向,遷移後刪除舊檔,避免兩份配置漂移。

JSON 配置檔案怎麼加註釋?

標準 JSON 不支援註釋。可選方案有三種:改用 JSONC(VS Code 生態的方言,需要 jsonc-parser 讀取)、維護一份旁註文件說明欄位含義、或直接換成 TOML / YAML。對外傳輸的檔案仍建議保持標準 JSON,把說明放在文件或 Schema 裡。

TOML 和 YAML 哪個更適合應用配置?

結構扁平、以鍵值為主、需要日期型別時選 TOML,它的語意更確定,解析器差異更小。需要複雜巢狀、多文件、錨點重複使用,或者目標生態本身就是 YAML(Kubernetes、CI)時選 YAML。兩者都能寫註釋,真正的區分點是結構複雜度與生態綁定。

為什麼 YAML 裡 NO 會變成 false?

YAML 1.1 把 yes、no、on、off、y、n 都當作布林值,所以挪威的國家代碼 NO 會被解析成 false。這是「挪威問題」。規避方法有兩種:升級到按 YAML 1.2 解析的實作,或給所有可能被誤判的字串加上引號。

CSON 還值得用嗎?

新專案不建議。CSON 依賴 CoffeeScript 生態,現成工具少,編輯器與 CI 支援都有限,Atom 停止維護後使用情境進一步收縮。如果專案裡已有 CSON 配置,優先安排一次性遷移到 JSON、TOML 或 YAML,而不是繼續新增。