Data formats · 8 min read · Updated 2026
数据格式 · 阅读约 8 分钟 · 更新于 2026

JSON, YAML, TOML — A Quick Comparison

JSON、YAML、TOML 快速对比

Three text formats now share the job of "structured data humans can read and machines can parse". JSON, YAML, and TOML were each designed for a different purpose, and they each have a personality. Choosing the right one is not a matter of taste — it is about matching the format to the use case. This article shows the same data in all three, highlights the design trade-offs, and ends with a clear recommendation for each common situation.

如今,三种文本格式共同承担了"人可读、机可解析的结构化数据"这一任务。JSON、YAML、TOML 各自为不同目的而生,各有各的性格。选哪一种并非个人喜好问题 —— 而是要让格式匹配使用场景。本文用同样的数据展示这三种格式,剖析它们的设计权衡,并针对每种常见场景给出明确建议。

What each format is for

每种格式的定位

JSON — JavaScript Object Notation — was specified by Douglas Crockford in 2001 as a strict, simple data interchange format derived from JavaScript object literals. It is the lingua franca of web APIs: every major language has a parser, and the format is small enough to spec in a few pages. The cost is verbosity: keys must be quoted, strings must use double quotes, and there are no comments.

JSON(JavaScript Object Notation)由 Douglas Crockford 在 2001 年提出,源自 JavaScript 对象字面量,是一种严格、简洁的数据交换格式。它是 Web API 的通用语言:几乎所有主流语言都有解析器,规范也只需几页纸就能写完。代价是冗长:键必须加引号、字符串必须使用双引号、并且不支持注释。

YAML — "YAML Ain't Markup Language" — first released in 2001, aims to be a human-friendly data serialization standard. It uses indentation instead of braces, supports comments, and has rich type tags (dates, binary, sets). Its power comes with famous gotchas: the "Norway problem", surprise type coercions, and parsers that disagree on edge cases.

YAML("YAML Ain't Markup Language",最初发布于 2001 年)目标是成为对人类友好的数据序列化标准。它用缩进代替花括号,支持注释,并提供丰富的类型标签(日期、二进制、集合等)。强大的同时也有著名的陷阱:"挪威问题"、意外的类型转换,以及不同解析器在边界情况下的行为不一致。

TOML — Tom's Obvious Minimal Language — was created by Tom Preston-Werner (co-founder of GitHub) in 2013. It is designed to be obvious: key = "value" pairs grouped under [table] headers, much like the classic Windows INI file but with a clean type system. It is the configuration language of Rust's Cargo, Python's pyproject.toml, and many newer tools.

TOML(Tom's Obvious Minimal Language)由 GitHub 联合创始人 Tom Preston-Werner 于 2013 年创建。设计目标是"显然易读":key = "value" 的键值对以 [table] 表头分组,类似于经典的 Windows INI 文件,但拥有更干净的类型系统。它被 Rust 的 Cargo、Python 的 pyproject.toml 以及许多较新的工具用作配置语言。

The same data in three forms

同一份数据的三种写法

Imagine a small configuration describing a web service. Here it is in JSON:

假设有一份描述 Web 服务的小配置。JSON 写法:

{
  "name": "blog-api",
  "version": "1.4.2",
  "debug": false,
  "port": 8080,
  "allowed_hosts": ["example.com", "*.staging.example.com"],
  "database": {
    "host": "db.internal",
    "port": 5432,
    "user": "blog"
  }
}

The same data in YAML:

同一份数据用 YAML 写:

name: blog-api
version: 1.4.2
debug: false
port: 8080
allowed_hosts:
  - example.com
  - "*.staging.example.com"
database:
  host: db.internal
  port: 5432
  user: blog

And in TOML:

再用 TOML 写:

name = "blog-api"
version = "1.4.2"
debug = false
port = 8080
allowed_hosts = ["example.com", "*.staging.example.com"]

[database]
host = "db.internal"
port = 5432
user = "blog"

YAML is the most compact for this data; JSON is the most explicit; TOML is the most "key-value at a glance". All three encode exactly the same information. The differences are in how the eye scans them and how forgiving the parser is when the file is slightly malformed.

对这份数据而言,YAML 最紧凑;JSON 最显式;TOML 最"一眼即键值"。三者表达的信息完全相同,差别在于肉眼扫描时的感受,以及解析器对轻微格式错误的容忍程度。

Comments and multi-line strings

注释与多行字符串

JSON has no comment syntax. Period. The original Crockford spec removed comments because he feared implementations would diverge. The community has lived with this for twenty years through hacky workarounds: keys named "// comment", minified JSON in production with comments in a separate file, JSON5 or JSONC extensions in tooling. If you need comments in a JSON file, your format is wrong — switch to YAML or TOML.

JSON 不支持注释。真的没有。最初 Crockford 在规范中删除注释,是担心不同实现会产生分歧。社区二十年来靠各种笨拙方式绕过去:用 "// comment" 这种假键做注释、生产环境用压缩 JSON、注释放在单独文件里,或者在工具链中改用 JSON5、JSONC 等扩展。如果你真的需要在配置里加注释,那说明格式选错了 —— 换成 YAML 或 TOML 吧。

YAML supports comments with #, anywhere a key is allowed, and multi-line strings with | (literal, preserves newlines) or > (folded, joins lines with spaces). TOML supports comments with # as well, and multi-line strings with triple quotes """...""". Both are far friendlier than JSON for hand-edited configuration files.

YAML 允许在任何可以放键的地方用 # 写注释;多行字符串用 |(字面量,保留换行)或 >(折叠,把多行合并成空格)表示。TOML 也支持 # 注释,多行字符串用三引号 """..."""。对需要手工编辑的配置文件而言,两者都比 JSON 友好得多。

The famous YAML gotchas

YAML 的著名陷阱

YAML's flexibility is also its danger. The "Norway problem" happens because NO is a YAML 1.1 boolean meaning false. So if you write country: NO thinking it is a string for Norway, YAML parses it as a boolean and the field becomes false. Modern parsers default to YAML 1.2, which removes this ambiguity, but many libraries and old config files still use 1.1. Always quote country codes, ISO codes, and any short uppercase tokens: country: "NO".

YAML 的灵活性也是它的风险。"挪威问题"就源于:NO 在 YAML 1.1 中是布尔值 false。如果你写 country: NO 想表示挪威的字符串,YAML 会把它解析成布尔值,字段最终是 false。现代解析器默认采用 YAML 1.2,已经消除了这种歧义,但很多库和老配置仍按 1.1 处理。遇到国家代码、ISO 代码或任何较短的大写标记时,务必加引号:country: "NO"

The second gotcha is sexagesimal numbers. YAML 1.1 accepts base-60 numbers: phone: 0123 is decimal but phone: 12:34 becomes a number representing seconds and minutes — 754 — not the phone number you intended. Quoting helps: phone: "0123:45".

第二个陷阱是六十进制数字。YAML 1.1 接受 base-60 数字:phone: 0123 是十进制,但 phone: 12:34 会被解析成"12 分 34 秒"对应的十进制数字 754,而不是你想要的电话号码。解决方法是加引号:phone: "0123:45"

A third, less famous one: tabs. YAML does not allow tabs for indentation — only spaces. A single tab mixed in with two-space indentation will fail in confusing ways. Most editors can be configured to convert tabs to spaces on save, and that is a habit worth forming.

第三个不那么出名但同样坑人的问题是:制表符。YAML 不允许用 Tab 缩进 —— 只能使用空格。如果在两空格缩进里混进一个 Tab,错误信息会让人摸不着头脑。多数编辑器可以配置"保存时把 Tab 转为空格",这个习惯值得养成。

TOML's balance and modern role

TOML 的平衡与现代角色

TOML is the youngest of the three but is rapidly becoming the default for new project configuration. pyproject.toml in the Python world, Cargo.toml in Rust, and several newer JavaScript build tools all use it. The reason is that TOML sits in a sweet spot: keys and values are unambiguous, comments are supported, nested tables are explicit, and the parser is deterministic and fast.

TOML 是三者中最年轻的,却正在迅速成为新项目配置的默认选择。Python 世界的 pyproject.toml、Rust 的 Cargo.toml,以及一些较新的 JavaScript 构建工具都使用它。原因在于 TOML 恰好命中一个甜蜜点:键值明确、支持注释、嵌套表显式、解析器行为确定且快速。

The TOML syntax is also strictly typed: a value is a string, integer, float, boolean, array, datetime, or table. There is no coercion. port = 8080 is unambiguously the integer 8080, not the string "8080". The trade-off is verbosity — every key needs "" or explicit type, and arrays must use brackets — but for configuration files, that verbosity is a feature, not a bug. Configuration that is read more often than it is written deserves to be explicit.

TOML 语法是严格类型化的:一个值要么是字符串、整数、浮点、布尔、数组、日期时间,要么是表。没有任何隐式类型转换。port = 8080 明确就是整数 8080,而不是字符串 "8080"。代价是更冗长 —— 每个键需要 "" 或显式类型,数组必须使用方括号 —— 但对于配置文件来说,这种冗长是优点而非缺点。"读得比写得更多"的配置,理应写得显式。

TOML 1.0, however, had a controversial feature: dotted keys creating tables implicitly (database.host = "db.internal" was equivalent to a [database] table). TOML 1.1 (released in 2024) has tightened the spec to disallow this implicit nesting, making files easier to reason about. If you are starting a new project, target TOML 1.1.

不过 TOML 1.0 曾有一个有争议的特性:可以用点号键隐式创建表(database.host = "db.internal" 等价于一个 [database] 表)。2024 年发布的 TOML 1.1 收紧了规范,禁止这种隐式嵌套,让文件更易于理解。如果你在启动一个新项目,建议以 TOML 1.1 为目标。

When to pick which

什么时候选哪个

Use JSON when:

使用 JSON 的场景:

  • You are exchanging data between programs (HTTP APIs, message queues, log shipping).
  • 在程序之间交换数据(HTTP API、消息队列、日志传输)。
  • You need the widest possible parser support with the fewest surprises.
  • 需要最广泛的解析器支持,并且最不可能出意外。
  • The data is mostly generated by code and rarely hand-edited.
  • 数据主要由程序生成、几乎不手工编辑。

Use YAML when:

使用 YAML 的场景:

  • You are writing a file that humans will edit frequently (Kubernetes manifests, Ansible playbooks, GitHub Actions).
  • 需要频繁人工编辑的文件(Kubernetes manifest、Ansible playbook、GitHub Actions)。
  • You need cross-references (&anchor *ref) and complex structures like sets.
  • 需要交叉引用(&anchor *ref)以及集合等复杂结构。
  • You accept the responsibility of quoting string values to avoid the Norway problem.
  • 愿意承担"为避免挪威问题而给字符串加引号"的责任。

Use TOML when:

使用 TOML 的场景:

  • You are writing a new application's configuration file.
  • 在为新的应用编写配置文件。
  • You want explicit types and few surprises.
  • 希望类型显式、行为可预期。
  • You need comments but do not need YAML's full expressive power.
  • 需要注释,但不需要 YAML 完整的表达力。

Common pitfalls across all three

三者共同的常见坑

No matter which format you choose, a few habits save hours of debugging. First, always specify a schema: JSON Schema, a TOML schema, or a hand-written comment block at the top of the file. Second, validate configuration in CI with a linter — yamllint, taplo, ajv, check-jsonschema all exist for this. Third, never commit secrets: passwords, API keys, and tokens belong in environment variables or a secrets manager, not in source-controlled config files.

无论你选哪种格式,有几个习惯能节省大量调试时间。首先,务必指定 schema:JSON Schema、TOML schema,或在文件顶部手写一段说明注释。其次,在 CI 里用 linter 校验配置 —— yamllinttaploajvcheck-jsonschema 都是为此而生。第三,永远不要把密钥写进配置文件:密码、API key、token 都应该放在环境变量或专门的密钥管理服务里,而不是提交到源代码。

A subtle fourth point: encoding. All three formats are specified in UTF-8. Make sure your editor and your build tools agree. The single most common cause of "my config broke after I changed one thing" is an editor silently saving the file as UTF-16 or as UTF-8 with a BOM.

第四个容易忽略的点是编码。三种格式都规定使用 UTF-8。请确保你的编辑器和构建工具一致。出现"我只改了一行配置就崩了"的最常见原因,就是编辑器悄悄把文件另存为 UTF-16 或带 BOM 的 UTF-8。

Try the tools

试试这些工具

Format, validate, and inspect JSON with the JSON formatter. Paste raw JSON and see it pretty-printed, minified, or with keys sorted. The formatter also reports parse errors at the exact line and column where they occur, which is invaluable when debugging a malformed API response.

JSON 格式化工具 整理、校验、检查 JSON。粘贴原始 JSON,即可看到美化、压缩或按键排序的结果。该工具还能在出错时精确报告解析错误的行列位置,是调试格式错误 API 响应的利器。