JSON Toolkit

JSON, TOML, YAML hay CSON: chọn định dạng cấu hình

Kết luận: Tệp cấu hình cần chú thích, ngày tháng và văn bản nhiều dòng, đó là những chỗ JSON thiếu. Hãy so sánh JSON, TOML, YAML và CSON, và xem chuyển đổi luôn làm mất những gì.

Người mớiĐọc khoảng 9 phútXuất bản 2026-10-31Cập nhật 2026-10-31
Ảnh bìa so sánh các định dạng cấu hình JSON, TOML, YAML và CSON

Kết luận: dùng JSON cho trao đổi máy-máy, và chọn TOML hoặc YAML cho cấu hình do con người duy trì tùy theo hệ sinh thái (YAML cho Kubernetes và CI, TOML cho cấu trúc phẳng hoặc ngày tháng gốc); chỉ quay về JSONC khi bạn không chắc bên đọc có hỗ trợ biến thể đó hay không.

JSON tồn tại cho máy móc trao đổi dữ liệu; tệp cấu hình được con người viết cho con người. Trộn lẫn hai thứ này và bạn sẽ có một config.json không chứa được chú thích và chẳng ai dám rút gọn.

1. Trước hết, hãy phân biệt hai loại tệp

Trao đổi dữ liệu và cấu hình không cùng mục tiêu, dù cùng một người thường viết cả hai trên cùng một máy.

Khía cạnh Trao đổi dữ liệu Cấu hình
Ai viết Một chương trình tuần tự hóa giá trị Con người, hoặc con người sửa đầu ra được sinh tự động
Ai đọc Chương trình của người khác Chương trình của chính bạn
Điều quan trọng Không nhập nhằng, kích thước, tốc độ phân tích Dễ đọc, có chú thích, diff dễ xem xét
Tần suất thay đổi Mỗi yêu cầu Thỉnh thoảng, có xem xét
Chi phí của một lỗi Một phản hồi 500 Một dịch vụ không khởi động được

JSON gần như hoàn hảo ở cột bên trái: ngữ pháp tối giản, trình phân tích có trong mọi ngôn ngữ, và không có chú thích nên không có vấn đề "chú thích lệch khỏi giá trị". Ở cột bên phải, sự khắt khe của nó là ma sát thuần túy: không chú thích, không dấu phẩy cuối, không ngày tháng, và văn bản nhiều dòng phải gộp thành một dòng bằng \n.

2. Bốn ứng viên và cú pháp của chúng

  • JSON: do RFC 8259 và ECMA-404 định nghĩa, với đúng sáu kiểu giá trị: object, array, string, number, boolean và null. Đây là chuẩn trao đổi thực tế và là định dạng duy nhất không cần quyết định lựa chọn.
  • TOML: do Tom Preston-Werner tạo ra, với v1.0.0 công bố tháng 1 năm 2021. Mục tiêu đã nêu là một định dạng cấu hình tối giản với ngữ nghĩa rõ ràng, ánh xạ không nhập nhằng sang bảng băm. Cargo.toml và pyproject.toml dùng nó mặc định.
  • YAML: đặc tả hiện tại là 1.2.2. Thụt lề biểu diễn phân cấp, và nó hỗ trợ chú thích, anchor cùng nhiều tài liệu. Manifest Kubernetes, GitHub Actions và Ansible đều phụ thuộc vào nó, với cái giá là đặc tả lớn và các khác biệt trong hiện thực.
  • CSON: CoffeeScript Object Notation, viết cấu hình bằng literal đối tượng của CoffeeScript. config.cson của Atom từng dùng nó. Nó hỗ trợ chú thích, khóa không ngoặc kép và dấu phẩy cuối, nhưng hệ sinh thái của nó chưa bao giờ ra khỏi thế giới JavaScript.

2.1 So sánh năng lực

Năng lực JSON TOML YAML CSON
Chú thích ✗ ✓ # ✓ # ✓ #
Dấu phẩy cuối ✗ ✓ (mảng, bảng nội tuyến) ✓ (tập hợp flow) ✓
Khóa không ngoặc kép ✗ ✓ ✓ ✓
Ngày-giờ gốc ✗ (chỉ chuỗi) ✓ bốn kiểu ngày-giờ ✓ (tự phân tích ở 1.1) ✗
Chuỗi nhiều dòng ✗ (escape \n) ✓ """ và ''' ✓ scalar dạng khối và gấp ✓ heredoc
Phạm vi số nguyên Không giới hạn theo đặc tả, thực tế là double 64-bit có dấu, phải không mất dữ liệu Độ chính xác tùy ý cộng .inf/.nan Theo JavaScript
Lồng nhau Ngoặc nhọn và ngoặc vuông Bảng, mảng của bảng, khóa chấm Thụt lề Thụt lề
Nhạy cảm thụt lề ✗ ✗ ✓ ✓
null ✓ ✗ ✓ ✓
Độ phủ công cụ Mọi ngôn ngữ Ngôn ngữ phổ biến Mọi ngôn ngữ, hiện thực khác nhau Chỉ JavaScript

Hai ô đáng lưu ý. TOML không có null, đây là lỗi phổ biến nhất khi chuyển từ JSON. Hành vi "ngày tháng gốc" của YAML nghĩa là trình phân tích 1.1 tự biến 2026-10-31 thành đối tượng ngày, nên kiểu dữ liệu trôi khác nhau giữa các ngôn ngữ.

3. Chú thích: điểm yếu duy nhất của JSON

Kết luận trước: nếu con người duy trì tệp và cần giải thích vì sao một giá trị là như vậy, đừng dùng JSON chuẩn.

Có bốn hướng thực tế, xếp theo mức độ xâm lấn:

  1. Chuyển sang JSONC, tức JSON chuẩn cộng chú thích và dấu phẩy cuối. settings.json và tsconfig.json của VS Code dùng nó. Cái giá là bên đọc phải dùng trình phân tích hiểu chú thích như jsonc-parser; JSON.parse thuần sẽ lỗi. Chi tiết trong JSON5 và JSONC: JSON có chú thích.
  2. Giữ một tài liệu song hành. config.json vẫn máy đọc được, trong khi config.md giải thích từng trường nghĩa là gì và vì sao nó giữ giá trị đó. Cả hai nằm cùng thư mục và thay đổi trong cùng một commit.
  3. Đưa giải thích vào lược đồ. Các từ khóa description và $comment của JSON Schema có thể mô tả trường, nhưng lược đồ hiếm khi đi kèm cấu hình lúc chạy, nên người đọc cấu hình có thể không bao giờ thấy chúng.
  4. Chuyển sang TOML hoặc YAML, để chính định dạng cung cấp chú thích mà mọi trình phân tích đều hiểu.
{
  // 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 vẫn là một biến thể: phần mở rộng giữ là .json, nhưng chỉ một số công cụ hiểu nó. Khi dữ liệu rời khỏi nhóm hoặc vượt qua ranh giới dịch vụ, ranh giới giữa JSONC và JSON chuẩn phải được ghi lại trong tài liệu.

4. Ngày tháng và văn bản nhiều dòng: sân nhà của TOML

TOML nâng ngày-giờ thành kiểu hạng nhất với bốn biến thể: ngày-giờ có offset, ngày-giờ địa phương, ngày địa phương và giờ địa phương. Chuỗi nhiều dòng có cú pháp riêng giữ nguyên xuống dòng:

title = "json-toolkit"
created = 2026-10-31T09:00:00+08:00
description = """
A JSON toolkit for developers.
Every operation runs locally in the browser.
"""

Cùng thông tin đó trong JSON phải hạ ngày tháng xuống chuỗi và escape xuống dòng:

{
  "title": "json-toolkit",
  "created": "2026-10-31T09:00:00+08:00",
  "description": "A JSON toolkit for developers.\nEvery operation runs locally in the browser."
}

Trong JSON, "created" chỉ là một chuỗi tình cờ trông giống ngày tháng, nên thông tin kiểu phải nằm trong hợp đồng trường: cả hai bên phải đồng ý rằng trường này luôn theo RFC 3339. TOML cho trình phân tích một đối tượng ngày thật mà không cần thỏa thuận bằng lời.

YAML cũng chứa được văn bản nhiều dòng, nhưng hai kiểu khối mang ý nghĩa khác nhau: | giữ xuống dòng trong khi > gấp chúng thành dấu cách. Chọn sai kiểu thì một địa chỉ hoặc một câu lệnh SQL sẽ bị gộp thành một dòng, một lỗi rất khó phát hiện khi xem xét.

5. Số: khác biệt bị bỏ qua nhiều nhất

Đặc tả JSON không giới hạn độ chính xác số, nhưng RFC 8259 cũng cảnh báo rằng tương thích an toàn nhất khi số được xử lý như double IEEE 754. Trong JavaScript, số nguyên lớn hơn 2^53 - 1 mất độ chính xác một cách âm thầm:

JSON.parse('{"id":9007199254740993}').id
// 9007199254740992: the last digit is gone

TOML yêu cầu số nguyên 64-bit có dấu được xử lý không mất dữ liệu và phải báo lỗi thay vì cắt cụt âm thầm; số thực theo binary64 và có thể là inf hoặc nan. YAML 1.1 mang gánh nặng cũ: 1:30 được phân tích thành 90 (hệ lục thập phân), và boolean chấp nhận yes, no, on, off. Do đó có "vấn đề Na Uy" kinh điển, nơi mã quốc gia NO biến thành false.

Với tiền tệ, đừng bao giờ dựa vào dấu phẩy động trong bất kỳ định dạng nào ở trên: hãy dùng đơn vị tiền tệ nhỏ nhất dạng số nguyên, chuỗi, hoặc kiểu decimal của cơ sở dữ liệu. Định dạng và độ chính xác được trình bày sâu hơn trong ranh giới chuyển đổi JSON, YAML và XML.

6. Bảng và lồng nhau: ranh giới cứng của TOML

TOML biểu diễn lồng nhau bằng bảng và mảng của bảng:

[server]
port = 8080

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

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

Nó có hai ranh giới cứng bạn phải biết trước khi chuyển đổi:

  • Gốc của một tài liệu TOML là một bảng, nên một tài liệu JSON có cấp cao nhất là mảng (như [1, 2, 3]) không có biểu diễn TOML hợp lệ; nó phải được bọc thành {"items": [...]};
  • TOML không có null, nên một trường JSON null phải bị bỏ hoặc thay bằng chuỗi rỗng hay giá trị đánh dấu, với ngữ nghĩa bị đẩy sang bên tiêu thụ.

YAML thì ngược lại: độ sâu lồng nhau không giới hạn, và anchor cộng merge key có thể tái sử dụng các đoạn:

defaults: &defaults
  retries: 3
  timeoutMs: 5000

server:
  <<: *defaults
  port: 8080

Anchor là năng lực chỉ YAML có và chắc chắn mất khi chuyển đổi: JSON không có cú pháp tham chiếu, nên tệp sau khi mở rộng sẽ lớn hơn và không có gì ghi lại rằng hai phần từng là cùng một cấu hình.

7. Chọn theo tình huống

Tình huống Khuyến nghị Lý do
API công khai, hàng đợi tin nhắn, bộ nhớ đệm JSON Tính phổ quát tối đa, chi phí thương lượng bằng không
Cấu hình ứng dụng, phẳng và có kiểu TOML Chú thích, ngày tháng, số nguyên không mất dữ liệu, hành vi trình phân tích ổn định
Kubernetes, CI, Ansible YAML Hệ sinh thái đã cố định; đổi định dạng nghĩa là đổi công cụ
VS Code, tsconfig.json JSONC Được hỗ trợ sẵn, không cần đưa định dạng mới vào
Tái sử dụng các đoạn cấu hình YAML Anchor và merge key là lựa chọn sẵn có duy nhất
Sinh tự động và chỉ dành cho máy JSON (đã nén) Không cần chú thích, kích thước và chi phí phân tích tốt nhất
Dự án Atom hoặc CoffeeScript cũ CSON, nhưng lên kế hoạch di chuyển Hệ sinh thái rất hẹp và chi phí di chuyển tăng theo thời gian

Một quy tắc ngón tay cái: hãy để hệ sinh thái chọn định dạng cấu hình, không phải sở thích cá nhân. Viết Rust nghĩa là Cargo.toml, triển khai lên Kubernetes nghĩa là YAML, và xây extension VS Code nghĩa là JSONC. Chỉ trong một dự án mới không có ràng buộc hệ sinh thái thì "cái nào viết dễ hơn" mới là câu hỏi thật.

8. Ranh giới chuyển đổi

Hướng Thông tin luôn bị mất Lời khuyên
JSON → TOML null, mảng cấp cao nhất, khóa không biểu diễn được Chuẩn hóa cấu trúc và bỏ trường rỗng trước
TOML → JSON Chú thích, kiểu ngày tháng, inf / nan Chuyển ngày tháng thành chuỗi RFC 3339
YAML → JSON Chú thích, anchor và merge key, tag, nhiều tài liệu Mở rộng anchor trước, rồi chuyển từng tài liệu
JSON → YAML Không mất cấu trúc, nhưng chuỗi ngày có thể bị tự phân tích Đặt chuỗi ngày trong ngoặc kép
CSON → JSON Chú thích, biểu thức CoffeeScript Di chuyển một lần; đừng đồng bộ hai chiều

Công cụ chuyển đổi bảo đảm giá trị, không bao giờ bảo đảm chú thích. Vì vậy đừng thiết kế pipeline hai chiều kiểu "JSON là nguồn và YAML là sản phẩm build". Hoặc chỉ sinh theo một chiều, hoặc duy trì một tệp nguồn duy nhất.

9. Danh sách kiểm tra

  • [ ] Ghi lại loại tệp nào dùng định dạng nào, và liệt kê các biến thể được phép;
  • [ ] Ưu tiên TOML hoặc YAML cho cấu hình do con người duy trì, và JSON cho trao đổi máy-máy;
  • [ ] Lưu ngày tháng trong JSON dưới dạng chuỗi RFC 3339 và đánh dấu định dạng trong lược đồ;
  • [ ] Biểu diễn tiền tệ và số nguyên lớn hơn 2^53 dưới dạng chuỗi hoặc đơn vị nhỏ nhất, không bao giờ dùng số thực;
  • [ ] Kiểm tra từng định dạng trong CI bằng trình phân tích riêng, không bao giờ dùng JSON.parse cho YAML;
  • [ ] Chuyển định dạng chỉ theo một chiều, và xóa tệp cũ để hai bên không thể lệch nhau.

FAQ

Tại sao chuyển JSON sang TOML lại lỗi ở một số trường?

TOML không có null, và gốc của một tài liệu TOML là một bảng, nên một trường JSON null phải bị bỏ hoặc thay bằng chuỗi rỗng hay giá trị đánh dấu, còn mảng cấp cao nhất phải được bọc thành {"items": [...]}. Chú thích, kiểu ngày tháng và inf/nan cũng bị mất khi đi theo chiều ngược lại, đó là lý do việc chuyển đổi nên diễn ra một chiều.

Tôi có nên giữ hai tệp cấu hình ở hai định dạng khác nhau?

Không. Công cụ chuyển đổi bảo đảm giá trị nhưng không bao giờ bảo đảm chú thích, nên pipeline kiểu "JSON là nguồn và YAML là sản phẩm build" sẽ bị lệch. Hoặc chỉ sinh theo một chiều, hoặc duy trì một tệp nguồn duy nhất và xóa tệp cũ sau khi di chuyển.

Làm sao thêm chú thích vào tệp cấu hình JSON?

JSON chuẩn không có chú thích. Bạn có thể chuyển sang JSONC (biến thể của VS Code, đọc bằng jsonc-parser), giữ một tài liệu song hành giải thích từng trường, hoặc chuyển sang TOML hay YAML. Các tệp gửi cho hệ thống khác nên giữ JSON chuẩn, với giải thích nằm trong tài liệu hoặc lược đồ.

TOML hay YAML tốt hơn cho cấu hình ứng dụng?

Chọn TOML khi cấu trúc phẳng, chủ yếu là cặp khóa-giá trị và ngày tháng gốc có ý nghĩa; ngữ nghĩa của nó dễ dự đoán hơn và khác biệt giữa các trình phân tích nhỏ hơn. Chọn YAML khi bạn cần lồng sâu, nhiều tài liệu, tái sử dụng anchor, hoặc khi hệ sinh thái mục tiêu ưu tiên YAML như Kubernetes hay CI. Cả hai đều hỗ trợ chú thích, nên yếu tố khác biệt thật sự là độ phức tạp cấu trúc và mức cố định vào hệ sinh thái.

Tại sao NO biến thành false trong YAML?

YAML 1.1 coi yes, no, on, off, y và n là boolean, nên mã quốc gia NO của Na Uy bị phân tích thành false. Đây là "vấn đề Na Uy". Hãy tránh nó bằng cách dùng hiện thực theo YAML 1.2, hoặc đặt trong ngoặc kép mọi chuỗi có thể bị hiểu sai.

CSON còn đáng dùng không?

Không, với các dự án mới. CSON phụ thuộc vào hệ sinh thái CoffeeScript, ít công cụ được duy trì, và hỗ trợ trình biên tập cùng CI hạn chế; sau khi Atom ngừng được duy trì, các tình huống dùng nó càng thu hẹp thêm. Nếu một dự án đã có cấu hình CSON, hãy lên lịch di chuyển một lần sang JSON, TOML hoặc YAML thay vì viết thêm.