JSON、YAML 和 TOML 是软件开发中最流行的三种配置格式。每种格式都有各自的优势和取舍。本指南提供全面的对比分析,帮助你为项目选择合适的格式。
使用我们的免费工具在 JSON 和 YAML 之间即时转换 →
各格式概述
JSON(JavaScript 对象表示法)
JSON 由 Douglas Crockford 在 2000 年代初期提出,是一种源自 JavaScript 对象字面量语法的轻量级数据交换格式。其设计目标是简洁:用最少的规则使任何编程语言都能轻松解析。如今它是 Web API、配置文件(如 package.json 和 tsconfig.json)以及数据存储的事实标准。
YAML(YAML Ain't Markup Language)
YAML 于 2001 年由 Clark Evans、Ingy döt Net 和 Oren Ben-Kiki 首次提出。最初名为"Yet Another Markup Language",后更名以体现其面向数据(而非文档)的本质。YAML 为人类可读性而设计,广泛用于 DevOps 工具,如 Docker Compose、Kubernetes 清单、Ansible Playbook 以及 CI/CD 配置(GitHub Actions、GitLab CI)。
TOML(Tom 的明显最小化语言)
TOML 由 Tom Preston-Werner(GitHub 联合创始人)于 2013 年创建,专门作为一种最小化且无歧义的配置格式。其目标是语义明显、易于阅读,能清晰地映射到哈希表。TOML 是 Rust(Cargo.toml)、Python(pyproject.toml)和 Hugo 静态网站的标准配置格式。
语法对比
下面用三种格式表达相同的配置:
JSON
{
"server": {
"host": "localhost",
"port": 8080,
"debug": true
},
"database": {
"host": "db.example.com",
"port": 5432,
"name": "myapp",
"credentials": {
"username": "admin",
"password": "secret"
}
},
"features": ["auth", "logging", "cache"],
"max_connections": 100
}YAML
# Server configuration
server:
host: localhost
port: 8080
debug: true
# Database settings
database:
host: db.example.com
port: 5432
name: myapp
credentials:
username: admin
password: secret
features:
- auth
- logging
- cache
max_connections: 100TOML
# Server configuration
max_connections = 100
features = ["auth", "logging", "cache"]
[server]
host = "localhost"
port = 8080
debug = true
[database]
host = "db.example.com"
port = 5432
name = "myapp"
[database.credentials]
username = "admin"
password = "secret"功能对比
| 特性 | JSON | YAML | TOML |
|---|---|---|---|
| 注释 | 不支持 | 支持(#) | 支持(#) |
| 数据类型 | 字符串、数字、布尔值、null、数组、对象 | 字符串、整数、浮点数、布尔值、null、日期、数组、映射 + 自定义标签 | 字符串、整数、浮点数、布尔值、日期时间、数组、表 |
| 可读性 | 中等——大括号和引号增加视觉噪音 | 高——基于缩进的简洁语法 | 高——类 INI 格式,段落分明 |
| 严格性 | 非常严格——不允许尾随逗号和注释 | 宽松——隐式类型推断可能产生意外 | 严格——显式类型,极少歧义 |
| 工具支持 | 出色——所有语言都有原生解析器 | 良好——所有主流语言都有解析器 | 良好——在 Rust/Python/Go 中支持良好 |
| 多行字符串 | 不支持(使用 \n 转义序列) | 支持(| 保留换行,> 折叠换行) | 支持(三引号字符串) |
何时使用各格式
使用 JSON 的场景
- 构建或使用 REST API——JSON 是通用的 API 载荷格式
- 使用 package.json、tsconfig.json 或 composer.json
- 存储机器读取多于人类读取的数据(日志、导出)
- 需要最广泛的工具和解析器支持
- 不同编程语言之间的数据交换
// Typical JSON use cases
// package.json
{
"name": "my-app",
"version": "1.0.0",
"scripts": {
"dev": "next dev",
"build": "next build"
}
}
// tsconfig.json
{
"compilerOptions": {
"target": "ES2020",
"module": "ESNext",
"strict": true
}
}使用 YAML 的场景
- 编写 Docker Compose 文件或 Kubernetes 清单
- 配置 CI/CD 流水线(GitHub Actions、GitLab CI、CircleCI)
- 使用 Ansible Playbook 或 Helm Charts
- 需要在配置中添加注释
- 人类可读性是首要考虑且能保持缩进规范
# Docker Compose
services:
web:
image: nginx:alpine
ports:
- "80:80"
volumes:
- ./html:/usr/share/nginx/html
# GitHub Actions
name: CI
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci
- run: npm test使用 TOML 的场景
- 配置 Rust 项目(Cargo.toml)
- 配置 Python 项目(pyproject.toml、Poetry、Black、Ruff)
- 配置 Hugo 静态网站生成器
- 需要无隐式类型转换的明确格式
- 配置有清晰的分组结构(TOML 的表很适合这种情况)
# Cargo.toml (Rust)
[package]
name = "my-app"
version = "0.1.0"
edition = "2021"
[dependencies]
serde = { version = "1.0", features = ["derive"] }
tokio = { version = "1", features = ["full"] }
# pyproject.toml (Python)
[project]
name = "my-package"
version = "1.0.0"
requires-python = ">=3.9"
[tool.ruff]
line-length = 88
target-version = "py39"常见陷阱
YAML:缩进问题
YAML 使用缩进定义结构。混用制表符和空格,或缩进层级不一致,是 YAML 最常见的错误来源。
# BAD: mixing tabs and spaces (invisible but breaks YAML)
services:
web: # tab character - YAML error!
image: nginx
# BAD: inconsistent indentation
services:
web:
image: nginx # 4 spaces here
ports: # 2 spaces here - error!
- "80:80"
# GOOD: consistent 2-space indentation
services:
web:
image: nginx
ports:
- "80:80"YAML:"挪威问题"
在 YAML 1.1 中,未加引号的 NO、yes、on、off 会被解释为布尔值。国家代码"NO"(挪威)会变成 false。这已导致了实际的 Bug。YAML 1.2 修复了这一问题,但很多解析器仍默认使用 1.1 的行为。
# The "Norway Problem" - YAML 1.1
countries:
- name: Norway
code: NO # Parsed as boolean false!
- name: Sweden
code: SE # Parsed as string "SE"
- name: Finland
code: FI # Parsed as string "FI"
# Other surprising boolean values in YAML 1.1:
truthy: yes # boolean true
falsy: no # boolean false
enabled: on # boolean true
disabled: off # boolean false
positive: TRUE # boolean true
negative: False # boolean false
# FIX: Always quote values that could be misinterpreted
countries:
- name: Norway
code: "NO" # Now correctly a string
- name: Sweden
code: "SE"
settings:
enabled: "yes" # Now correctly a stringJSON:尾随逗号
JSON 不允许尾随逗号。在数组或对象的最后一个元素后加逗号会导致解析错误。这是手动编辑 JSON 文件时最常见的错误之一。
// BAD: trailing comma after last element
{
"name": "my-app",
"version": "1.0.0",
"private": true, // <-- trailing comma = PARSE ERROR
}
// BAD: trailing comma in array
{
"colors": [
"red",
"green",
"blue", // <-- trailing comma = PARSE ERROR
]
}
// GOOD: no trailing commas
{
"name": "my-app",
"version": "1.0.0",
"private": true
}TOML:嵌套表语法
TOML 中的深层嵌套结构可能变得冗长。每一层都需要自己的 [section.subsection] 头部,对于复杂层级关系来说不如 JSON 或 YAML 的嵌套直观。
# TOML: deeply nested config can be verbose
[server]
host = "localhost"
[server.ssl]
enabled = true
[server.ssl.certificates]
cert = "/path/to/cert.pem"
key = "/path/to/key.pem"
[server.ssl.certificates.ca]
bundle = "/path/to/ca-bundle.pem"
# The same in YAML is more compact:
# server:
# host: localhost
# ssl:
# enabled: true
# certificates:
# cert: /path/to/cert.pem
# key: /path/to/key.pem
# ca:
# bundle: /path/to/ca-bundle.pem
# TOML inline tables can help for shallow nesting:
[server]
host = "localhost"
ssl = { enabled = true, cert = "/path/to/cert.pem" }转换工具
需要在格式之间切换?使用我们的免费在线转换器:
TOML ↔ YAML 转换器——在 TOML 和 YAML 之间即时转换
常见问题
JSON、YAML 和 TOML 哪个解析最快?
JSON 通常解析最快,因为其语法简单严格。大多数 JSON 解析器已高度优化且有原生实现。TOML 由于语法无歧义也很快。YAML 通常最慢,因为其规范复杂,包含锚点、自定义标签和隐式类型推断等特性。
JSON 能使用注释吗?
标准 JSON(RFC 8259)不支持注释。JSON5 和 JSONC(VS Code 设置使用的格式)等工具扩展了 JSON 以支持注释,但这些是非标准的。如果需要注释,可以考虑使用 YAML 或 TOML,或使用在解析前去除注释的 JSON 预处理器。
为什么 YAML 把 "NO" 当作 false?
在 YAML 1.1 中,yes/no、on/off 和 true/false 都被识别为布尔值(不区分大小写)。因此国家代码"NO"会被解释为布尔值 false。这被称为"挪威问题"。为避免此问题,对可能被误解的字符串值始终加引号:使用 "NO" 而不是 NO。YAML 1.2 将布尔值限制为仅 true/false,但许多解析器仍默认使用 YAML 1.1 规则。
TOML 比 YAML 更适合配置文件吗?
TOML 通常被认为更适合简单、扁平的配置文件,因为它没有隐式类型转换,比 YAML 更不容易出错。但 YAML 处理深层嵌套和复杂结构更优雅。在 Rust 和 Python 生态中,TOML 是标准选择;在 DevOps 和 Kubernetes 领域,YAML 仍占主导地位。
在 JSON、YAML 和 TOML 之间转换会丢失数据吗?
对于大多数常见数据结构(字符串、数字、布尔值、数组、对象),三种格式之间的转换是无损的。但某些特性是格式特有的:YAML 的锚点和自定义标签在 JSON 或 TOML 中没有等价物;TOML 的日期时间类型在 JSON 中可能丢失精度;JSON 不支持注释,因此从 YAML/TOML 转换到 JSON 会丢失所有注释。