JSON, TOML, YAML หรือ CSON: การเลือกไฟล์กำหนดค่า
สรุปสำคัญ: ไฟล์กำหนดค่าต้องการ comment วันที่ และข้อความหลายบรรทัด ซึ่งเป็นจุดที่ JSON ทำไม่ได้ เปรียบเทียบ JSON, TOML, YAML และ CSON และดูว่าการแปลงสูญเสียอะไรเสมอ

สรุปสั้น: ใช้ JSON สำหรับการแลกเปลี่ยนระหว่างเครื่อง และเลือก TOML หรือ YAML สำหรับไฟล์กำหนดค่าที่มนุษย์ดูแลตามระบบนิเวศ (YAML สำหรับ Kubernetes และ CI, TOML สำหรับโครงสร้างแบบแบนหรือวันที่โดยธรรมชาติ); ถอยไปใช้ JSONC เฉพาะเมื่อไม่แน่ใจว่าตัวอ่านรองรับภาษาถิ่น
JSON มีอยู่เพื่อเครื่องแลกเปลี่ยนข้อมูล ส่วนไฟล์กำหนดค่าถูกเขียนโดยคนเพื่อคน ผสมสองอย่างเข้าด้วยกันคุณจะได้
config.jsonที่ใส่ comment ไม่ได้และไม่มีใครกล้าตัดอะไรออก
1. เริ่มจากไฟล์สองชนิดที่ต่างกัน
การแลกเปลี่ยนข้อมูลและการกำหนดค่าไม่ได้มีเป้าหมายเดียวกัน แม้คนคนเดียวกันมักเขียนทั้งสองอย่างบนเครื่องเดียวกัน
| มิติ | การแลกเปลี่ยนข้อมูล | การกำหนดค่า |
|---|---|---|
| ใครเขียน | โปรแกรมที่ serialize ค่า | มนุษย์ หรือมนุษย์ที่แก้ไขเอาต์พุตที่สร้างขึ้น |
| ใครอ่าน | โปรแกรมของคนอื่น | โปรแกรมของคุณเอง |
| อะไรสำคัญ | ไม่กำกวม, ขนาด, ความเร็ว parse | อ่านง่าย, comment, diff ที่รีวิวได้ |
| ความถี่ในการเปลี่ยน | ทุกคำขอ | เป็นครั้งคราว พร้อมการรีวิว |
| ต้นทุนของข้อผิดพลาด | response 500 | service ที่ไม่ยอมเริ่มทำงาน |
JSON ได้คะแนนเกือบเต็มในคอลัมน์ซ้าย: ไวยากรณ์มินิมัล, parser มีทุกภาษา และการไม่มี comment หมายถึงไม่มีปัญหา "comment ห่างเหินจากค่า" ในคอลัมน์ขวา ความเข้มงวดของมันคือแรงเสียดทานล้วน: ไม่มี comment, ไม่มี trailing comma, ไม่มีวันที่ และข้อความหลายบรรทัดต้องยุบเป็นบรรทัดเดียวด้วย \n
2. ผู้แข่งขันสี่รายและไวยากรณ์ของพวกมัน
- JSON: นิยามโดย RFC 8259 และ ECMA-404 มีชนิดค่าหกแบบพอดี: object, array, string, number, boolean และ
nullเป็นมาตรฐานการแลกเปลี่ยนโดยพฤตินัยและเป็นรูปแบบเดียวที่ไม่ต้องตัดสินใจเลือก - TOML: สร้างโดย Tom Preston-Werner โดย v1.0.0 เผยแพร่ในเดือนมกราคม 2021 เป้าหมายที่ประกาศไว้คือรูปแบบกำหนดค่ามินิมัลที่มีความหมายชัดเจนและ map กับ hash table อย่างไม่กำกวม
Cargo.tomlและpyproject.tomlใช้มันเป็นค่าเริ่มต้น - YAML: สเปกปัจจุบันคือ 1.2.2 การย่อหน้าแสดงลำดับชั้น และรองรับ comment, anchor และหลายเอกสาร Kubernetes manifest, GitHub Actions และ Ansible ต่างพึ่งมัน ด้วยต้นทุนเป็นสเปกขนาดใหญ่และความแตกต่างระหว่าง implementation
- CSON: CoffeeScript Object Notation ซึ่งเขียน configuration ด้วย object literal ของ CoffeeScript
config.csonของ Atom เคยใช้มัน มันรองรับ comment, คีย์ที่ไม่ใส่เครื่องหมายคำพูด และ trailing comma แต่ระบบนิเวศของมันไม่เคยออกจากโลก JavaScript
2.1 เปรียบเทียบความสามารถ
| ความสามารถ | JSON | TOML | YAML | CSON |
|---|---|---|---|---|
| Comment | ✗ | ✓ # |
✓ # |
✓ # |
| Trailing comma | ✗ | ✓ (array, inline table) | ✓ (flow collection) | ✓ |
| คีย์ที่ไม่ใส่เครื่องหมายคำพูด | ✗ | ✓ | ✓ | ✓ |
| วันที่-เวลาโดยธรรมชาติ | ✗ (string เท่านั้น) | ✓ ชนิดวันที่-เวลาสี่แบบ | ✓ (parse อัตโนมัติใน 1.1) | ✗ |
| String หลายบรรทัด | ✗ (escape \n) |
✓ """ และ ''' |
✓ block และ folded scalar | ✓ heredoc |
| ช่วงจำนวนเต็ม | ไม่จำกัดในสเปก แต่เป็น double ในทางปฏิบัติ | 64 บิตมีเครื่องหมาย ต้องไม่สูญเสีย | ความแม่นยำตามอำเภอใจบวก .inf/.nan |
ตาม JavaScript |
| การซ้อน | วงเล็บปีกกาและวงเล็บเหลี่ยม | table, array ของ table, dotted key | การย่อหน้า | การย่อหน้า |
| ไวต่อการย่อหน้า | ✗ | ✗ | ✓ | ✓ |
null |
✓ | ✗ | ✓ | ✓ |
| การครอบคลุมเครื่องมือ | ทุกภาษา | ภาษากระแสหลัก | ทุกภาษา แต่ implementation ต่างกัน | JavaScript เท่านั้น |
สองช่องที่ควรสังเกต TOML ไม่มี null ซึ่งเป็นความล้มเหลวที่พบบ่อยที่สุดเมื่อแปลงจาก JSON พฤติกรรม "วันที่โดยธรรมชาติ" ของ YAML หมายความว่า parser 1.1 เปลี่ยน 2026-10-31 เป็น object วันที่โดยอัตโนมัติ ชนิดจึงเลื่อนไปมาตามภาษา
3. Comment: จุดอ่อนเดียวของ JSON
บทสรุปก่อน: หากมนุษย์ดูแลไฟล์และต้องอธิบายว่าทำไมค่าจึงเป็นเช่นนั้น อย่าใช้ JSON มาตรฐาน
มีเส้นทางปฏิบัติสี่แบบ เรียงตามระดับความรุกราน:
- เปลี่ยนไปใช้ JSONC ซึ่งคือ JSON มาตรฐานบวก comment และ trailing comma
settings.jsonและtsconfig.jsonของ VS Code ใช้มัน ต้นทุนคือตัวอ่านต้องใช้ parser ที่เข้าใจ comment เช่นjsonc-parser;JSON.parseธรรมดาจะล้มเหลว รายละเอียดอยู่ใน JSON5 และ JSONC: JSON ที่มี comment - เก็บเอกสาร sidecar
config.jsonยังอ่านได้ด้วยเครื่อง ขณะที่config.mdอธิบายว่าฟิลด์แต่ละตัวหมายถึงอะไรและทำไมจึงมีค่านั้น ทั้งสองอยู่ในไดเรกทอรีเดียวกันและเปลี่ยนใน commit เดียวกัน - ใส่คำอธิบายใน schema keyword
descriptionและ$commentของ JSON Schema ใช้บันทึกฟิลด์ได้ แต่ schema ไม่ค่อยถูกส่งไปพร้อม configuration ตอนรัน คนที่อ่าน config จึงอาจไม่เคยเห็นมัน - ย้ายไป TOML หรือ YAML ให้รูปแบบเองมี comment ที่ทุก parser เข้าใจ
{
// Fixed at 8080: the frontend build script reads this port for its proxy
"port": 8080,
// Disable watching to avoid exhausting inodes in CI
"watch": false
}
JSONC ยังเป็นภาษาถิ่น: นามสกุลยังเป็น .json แต่มีเพียงบางเครื่องมือที่เข้าใจมัน เมื่อข้อมูลออกจากทีมหรือข้ามขอบเขต service เส้นแบ่งระหว่าง JSONC กับ JSON มาตรฐานต้องถูกบันทึกไว้
4. วันที่และ string หลายบรรทัด: บ้านของ TOML
TOML ยกระดับวันที่-เวลาเป็นชนิดชั้นหนึ่งโดยมีสี่แบบ: offset date-time, local date-time, local date และ local time String หลายบรรทัดมีไวยากรณ์เฉพาะที่รักษาการขึ้นบรรทัดใหม่:
title = "json-toolkit"
created = 2026-10-31T09:00:00+08:00
description = """
A JSON toolkit for developers.
Every operation runs locally in the browser.
"""
ข้อมูลเดียวกันใน JSON ต้องลดวันที่ลงเป็น string และ escape การขึ้นบรรทัดใหม่:
{
"title": "json-toolkit",
"created": "2026-10-31T09:00:00+08:00",
"description": "A JSON toolkit for developers.\nEvery operation runs locally in the browser."
}
ใน JSON "created" เป็นเพียง string ที่บังเอิญดูเหมือนวันที่ ข้อมูลชนิดจึงต้องอยู่ในสัญญาฟิลด์: ทั้งสองฝั่งต้องตกลงว่าฟิลด์นี้เป็น RFC 3339 เสมอ TOML ให้ object วันที่จริงกับ parser โดยไม่ต้องมีข้อตกลงด้วยวาจา
YAML ก็เก็บข้อความหลายบรรทัดได้ แต่ block สองสไตล์มีความหมายต่างกัน: | รักษาการขึ้นบรรทัดใหม่ ขณะที่ > พับมันเป็นช่องว่าง เลือกผิดแล้วที่อยู่หรือคำสั่ง SQL จะยุบเป็นบรรทัดเดียว ซึ่งเป็น error ที่จับได้ยากมากในการรีวิว
5. จำนวน: ความแตกต่างที่ถูกละเลยที่สุด
สเปก JSON ไม่จำกัดความแม่นยำของจำนวน แต่ RFC 8259 ยังเตือนว่าความเข้ากันได้ปลอดภัยที่สุดเมื่อถือจำนวนเป็น double ของ IEEE 754 ใน JavaScript จำนวนเต็มที่เกิน 2^53 - 1 สูญเสียความแม่นยำอย่างเงียบ ๆ:
JSON.parse('{"id":9007199254740993}').id
// 9007199254740992: the last digit is gone
TOML กำหนดให้จำนวนเต็ม 64 บิตมีเครื่องหมายถูกจัดการโดยไม่สูญเสีย และให้เกิด error แทนการตัดทิ้งอย่างเงียบ ๆ; float ตาม binary64 และอาจเป็น inf หรือ nan ได้ YAML 1.1 แบกภาระเก่า: 1:30 ถูก parse เป็น 90 (sexagesimal) และ boolean ยอมรับ yes, no, on และ off จึงเกิด "Norway problem" อันโด่งดังที่รหัสประเทศ NO กลายเป็น false
สำหรับเงิน อย่าพึ่ง floating point ในรูปแบบใดเหล่านี้เด็ดขาด: ใช้หน่วยย่อยเป็นจำนวนเต็ม, string หรือชนิด decimal ของฐานข้อมูล การจัดรูปแบบและความแม่นยำมีรายละเอียดเพิ่มเติมใน ขอบเขตของการแปลง JSON, YAML และ XML
6. Table และการซ้อน: ขอบเขตแข็งของ TOML
TOML แสดงการซ้อนด้วย table และ array ของ table:
[server]
port = 8080
[[routes]]
path = "/parse"
method = "POST"
[[routes]]
path = "/minify"
method = "POST"
มีขอบเขตแข็งสองข้อที่ต้องรู้ก่อนแปลง:
- root ของเอกสาร TOML เป็น table เอกสาร JSON ที่ระดับบนสุดเป็น array (เช่น
[1, 2, 3]) จึงไม่มีตัวแทน TOML ที่ถูกกฎหมาย; ต้องห่อเป็น{"items": [...]}; - TOML ไม่มี
nullฟิลด์nullใน JSON จึงต้องถูกลบหรือแทนที่ด้วย string ว่างหรือค่า sentinel โดยผลักความหมายไปให้ผู้บริโภค
YAML ตรงกันข้าม: ความลึกของการซ้อนไม่จำกัด และ anchor บวก merge key ใช้ชิ้นส่วนซ้ำได้:
defaults: &defaults
retries: 3
timeoutMs: 5000
server:
<<: *defaults
port: 8080
Anchor เป็นความสามารถเฉพาะ YAML และรับประกันว่าจะสูญเสียระหว่างการแปลง: JSON ไม่มีไวยากรณ์อ้างอิง ไฟล์ที่ขยายแล้วจึงโตขึ้นและไม่มีอะไรบันทึกว่าสองส่วนเคยเป็น configuration เดียวกัน
7. การเลือกตามสถานการณ์
| สถานการณ์ | คำแนะนำ | เหตุผล |
|---|---|---|
| API สาธารณะ, message queue, แคช | JSON | ความเป็นสากลสูงสุด, ต้นทุนการเจรจาเป็นศูนย์ |
| Config ของแอป แบนและมีชนิด | TOML | Comment, วันที่, จำนวนเต็มไม่สูญเสีย, พฤติกรรม parser เสถียร |
| Kubernetes, CI, Ansible | YAML | ระบบนิเวศถูกล็อกไว้; เปลี่ยนรูปแบบคือเปลี่ยนเครื่องมือ |
VS Code, tsconfig.json |
JSONC | รองรับโดยธรรมชาติ ไม่ต้องนำรูปแบบใหม่เข้ามา |
| ใช้ชิ้นส่วน configuration ซ้ำ | YAML | Anchor และ merge key เป็นตัวเลือกสำเร็จรูปเดียว |
| สร้างโดยเครื่องและใช้กับเครื่องเท่านั้น | JSON (minified) | ไม่ต้องมี comment ขนาดและต้นทุน parse ดีที่สุด |
| โปรเจกต์ Atom หรือ CoffeeScript เดิม | CSON แต่วางแผนย้าย | ระบบนิเวศชายขอบและต้นทุนการย้ายโตตามเวลา |
กฎง่าย ๆ: ให้ระบบนิเวศเลือกไฟล์กำหนดค่า ไม่ใช่ความชอบส่วนตัว เขียน Rust ก็ต้อง Cargo.toml deploy ไป Kubernetes ก็ต้อง YAML สร้างส่วนขยาย VS Code ก็ต้อง JSONC เฉพาะในโปรเจกต์ใหม่ที่ไม่มีข้อจำกัดจากระบบนิเวศ "อันไหนเขียนสนุกกว่า" จึงเป็นคำถามจริง
8. ขอบเขตของการแปลง
| ทิศทาง | ข้อมูลที่สูญเสียเสมอ | คำแนะนำ |
|---|---|---|
| JSON → TOML | null, array ระดับบนสุด, คีย์ที่แสดงไม่ได้ |
ปรับโครงสร้างให้เป็นมาตรฐานและตัดฟิลด์ว่างก่อน |
| TOML → JSON | Comment, ชนิดวันที่, inf / nan |
แปลงวันที่เป็น string RFC 3339 |
| YAML → JSON | Comment, anchor และ merge key, tag, หลายเอกสาร | ขยาย anchor ก่อน แล้วแปลงทีละเอกสาร |
| JSON → YAML | ไม่สูญเสียโครงสร้าง แต่ string วันที่อาจถูก parse อัตโนมัติ | ใส่เครื่องหมายคำพูดให้ string วันที่ |
| CSON → JSON | Comment, expression ของ CoffeeScript | ย้ายครั้งเดียว อย่าซิงก์สองทาง |
เครื่องมือแปลงรับประกันค่า ไม่เคยรับประกัน comment ดังนั้นอย่าออกแบบ pipeline สองทางที่ "JSON เป็นแหล่งและ YAML เป็น build artifact" ให้สร้างทางเดียว หรือดูแลไฟล์แหล่งเดียว
9. รายการตรวจสอบ
- [ ] บันทึกว่าไฟล์ชนิดไหนใช้รูปแบบไหน และระบุภาษาถิ่นที่อนุญาต;
- [ ] เลือก TOML หรือ YAML สำหรับ configuration ที่มนุษย์ดูแล และ JSON สำหรับการแลกเปลี่ยนระหว่างเครื่อง;
- [ ] เก็บวันที่ใน JSON เป็น string RFC 3339 และระบุรูปแบบใน schema;
- [ ] แทนเงินและจำนวนเต็มที่เกิน
2^53ด้วย string หรือหน่วยย่อย อย่าใช้ float; - [ ] ตรวจแต่ละรูปแบบใน CI ด้วย parser ของมันเอง อย่าใช้
JSON.parseกับ YAML; - [ ] ย้ายรูปแบบทางเดียวเท่านั้น และลบไฟล์เก่าเพื่อไม่ให้สองไฟล์เลื่อนออกจากกัน
คำถามที่พบบ่อย
ทำไมการแปลง JSON เป็น TOML จึงล้มเหลวกับบางฟิลด์?
TOML ไม่มี null และ root ของเอกสาร TOML เป็น table ฟิลด์ null ใน JSON จึงต้องถูกลบหรือแทนที่ด้วย string ว่างหรือ sentinel และ array ระดับบนสุดต้องห่อเป็น {"items": [...]} Comment, ชนิดวันที่ และ inf/nan ก็สูญเสียเมื่อไปในทิศทางตรงข้าม ซึ่งเป็นเหตุผลว่าการแปลงควรเป็นทางเดียว
ควรเก็บไฟล์กำหนดค่าสองไฟล์ในรูปแบบต่างกันหรือไม่?
ไม่ เครื่องมือแปลงรับประกันค่าแต่ไม่เคยรับประกัน comment pipeline ที่ "JSON เป็นแหล่งและ YAML เป็น build artifact" จะเลื่อนออกจากกัน ให้สร้างทางเดียว หรือดูแลไฟล์แหล่งเดียวและลบไฟล์เก่าหลังย้าย
จะเพิ่ม comment ให้ไฟล์กำหนดค่า JSON ได้อย่างไร?
JSON มาตรฐานไม่มี comment คุณเปลี่ยนไปใช้ JSONC (ภาษาถิ่นของ VS Code อ่านด้วย jsonc-parser) เก็บเอกสาร sidecar ที่อธิบายแต่ละฟิลด์ หรือย้ายไป TOML หรือ YAML ไฟล์ที่ส่งให้ระบบอื่นควรเป็น JSON มาตรฐาน โดยคำอธิบายอยู่ในเอกสารหรือ schema
TOML หรือ YAML ดีกว่าสำหรับ configuration ของแอป?
เลือก TOML เมื่อโครงสร้างแบน เป็นคู่คีย์-ค่าส่วนใหญ่ และวันที่โดยธรรมชาติสำคัญ; ความหมายคาดเดาได้กว่าและความต่างระหว่าง parser เล็กกว่า เลือก YAML เมื่อต้องซ้อนลึก หลายเอกสาร ใช้ anchor ซ้ำ หรือเมื่อระบบนิเวศเป้าหมายเป็น YAML เป็นหลัก เช่น Kubernetes หรือ CI ทั้งสองรองรับ comment ตัวแยกความแตกต่างจริงจึงคือความซับซ้อนเชิงโครงสร้างและการล็อกกับระบบนิเวศ
ทำไม NO กลายเป็น false ใน YAML?
YAML 1.1 ถือ yes, no, on, off, y และ n เป็น boolean รหัสประเทศ NO ของนอร์เวย์จึงถูก parse เป็น false นี่คือ "Norway problem" หลีกเลี่ยงด้วย implementation ที่ตาม YAML 1.2 หรือใส่เครื่องหมายคำพูดให้ string ทุกตัวที่อาจถูกตีความผิด
CSON ยังคุ้มใช้หรือไม่?
ไม่สำหรับโปรเจกต์ใหม่ CSON พึ่งระบบนิเวศ CoffeeScript มีเครื่องมือที่ได้รับการดูแลน้อย และรองรับใน editor กับ CI จำกัด; หลังจาก Atom หยุดได้รับการดูแล กรณีใช้งานก็หดลงอีก หากโปรเจกต์มี configuration แบบ CSON อยู่แล้ว ให้วางแผนย้ายครั้งเดียวไปยัง JSON, TOML หรือ YAML แทนการเพิ่มมันเข้าไปอีก