TOML 深度调研:对比 YAML、JSON 等五大配置格式,哪种最适合你的项目?

作者:王若风日期:2026/5/6

ChatGPT Image 2026年5月6日 22_39_09.png

大家好,我是若风。

上周在配置一个 Rust 项目的时候,我盯着 Cargo.toml 发了一会儿呆。然后突然意识到一件事:我写了这么多年代码,跟配置文件打交道的时间可能比写业务逻辑还多。package.jsondocker-compose.ymltsconfig.json.gitignoreterraform.tf……每个项目至少 3 到 5 个配置文件。

但说实话,我从来没认真想过一个问题:为什么这些工具要用不同的配置格式?

YAML 写 Kubernetes 配置,JSON 写 package.json,TOML 写 Cargo.toml,HCL 写 Terraform——这些选择是随机的,还是各有道理?

带着这个疑问,我做了一次深度调研。这篇文章就是调研结果。

先说结论

如果你在为新项目选配置格式,2026 年的默认推荐是 TOML,除非你遇到以下情况:

  1. 场景是数据交换——用 JSON
  2. 工具链强制要求 YAML(如 Kubernetes、GitHub Actions)——用 YAML
  3. 你在写 Terraform——用 HCL

下面展开讲为什么。

TOML 是什么?

TOML 的全称是 Tom's Obvious, Minimal Language——Tom 的显而易见的极简语言。注意,它不是递归缩写,也不是回文;只是一个名字很直白的配置格式。

创建者是 GitHub 联合创始人 Tom Preston-Werner,最早在 2013 年公开。它的设计动机很直接:做一个比 INI 更有类型、比 YAML 更少歧义、比 JSON 更适合人手写的配置格式。

具体来说,Tom 忍不了这几件事:

YAML 规范和生态都比较复杂,很多问题来自旧版 YAML 1.1 规则以及解析器兼容行为:比如 NOyesonoff 可能被解析成布尔值,1:30 在部分旧规则里可能被当作 sexagesimal 数字处理。YAML 1.2 已经收紧了这些隐式类型规则,但现实世界里的解析器和工具链并不总是严格按 1.2 行为走。同一份 YAML 文件在不同语言、不同解析器、不同版本下可能产生不同结果,这是它最让人头疼的地方。

Tom 的目标很清晰:做一个更好版本的 INI。语义明显、无歧义、最小化。能无歧义地映射到哈希表。

TOML 的核心特性

TOML 有一套丰富且严格的类型系统,这是它区别于 INI 的核心优势。

八种数据类型

1# 字符串——支持四种写法
2title = "TOML Example"                    # 基本字符串(支持转义)
3path = 'C:\Users\name\docs'               # 字面量字符串(原样输出,不转义)
4description = """可以换行的
5多行字符串"""
6regex = '''I [dw]on't need \d{2} apples''' # 多行字面量字符串
7
8# 整数——支持进制转换和下划线分隔
9port = 8080
10hex_color = 0xDEAD                         # 十六进制
11permissions = 0o755                        # 八进制
12big_num = 1_000_000                        # 下划线分隔,提升可读性
13
14# 浮点数——支持 inf  nan
15pi = 3.14159
16special = inf
17
18# 布尔值——只有 true/false,不会搞出什么 yes/no/on/off
19debug = true
20
21# 日期时间——四种类型,是 TOML 相对 JSON/INI 更完整的地方
22created = 2023-01-11T08:30:00Z            # 带时区
23deadline = 2023-12-31T23:59:59            # 不带时区
24birthday = 1990-05-27                      # 纯日期
25alarm = 07:30:00                           # 纯时间
26

集合类型

1# 数组——v1.0/v1.1 允许混合类型,但配置实践中更建议保持同构
2ports = [80, 443, 8080]
3mixed = ["admin", 42, true]                # 合法,但不一定推荐
4
5# 表(Table)——即字典/哈希表
6[database]
7server = "192.168.1.1"
8ports = [8001, 8001, 8002]
9
10# 嵌套表
11[database.connection]
12max_open = 100
13
14# 内联表——单行紧凑写法
15point = { x = 1, y = 2 }
16
17# 数组表——用双方括号,每个块是数组中的一个元素
18[[products]]
19name = "Hammer"
20sku = 738594937
21
22[[products]]
23name = "Nail"
24sku = 284758393
25

这些特性覆盖了配置文件的几乎所有需求。跟 INI 比,功能丰富太多了;跟 YAML 比,每一条的语义都是明确的,没有隐式推断。

TOML 的版本演进

TOML 从 2013 年到现在,经历了一个从快速迭代到稳定规范的过程:

版本时间关键变化
v0.1.x2013 年初始阶段,确立键值对、表、数组等基础语法
v0.2.x2013 年补充日期时间、多行字符串、数组表 [[table]] 等能力
v0.3.x2014-2015 年引入点分隔键、内联表等更完整的结构表达
v0.5.02018 年允许混合类型数组,补充十六进制、八进制、二进制整数
v1.0.02021 年 1 月 11 日首个稳定版,成为多数生态的兼容基线
v1.1.02025 年 12 月 18 日当前最新规范,增加少量语法便利性,例如 \e、\xHH 转义,以及部分日期时间场景可省略秒

截至 2026 年 5 月,TOML v1.1.0 是当前最新规范。不过很多语言标准库和主流工具仍以 v1.0.0 为兼容基线,例如 Python 3.11+ 标准库 tomllib 明确解析 TOML 1.0.0。因此实际选型时可以这样理解:v1.0.0 是最稳的跨生态底座,v1.1.0 是最新规范方向。

谁在用 TOML?

TOML 的采用不是靠营销,而是靠一个个具体的技术决策。

Rust:Cargo.toml

TOML 与 Rust 生态有很深的渊源。Cargo 使用 Cargo.toml,也是 TOML 获得广泛关注的重要起点。Rust 社区偏好显式和可预测的行为,跟 TOML 的“无歧义”理念很匹配。

Python:pyproject.toml

这是近十年最重要的配置格式迁移案例之一。Python 社区通过一系列 PEP 和 PyPA 规范,把构建系统依赖、项目元数据和工具配置逐步集中到 pyproject.toml。但它不是“一夜之间替代所有遗留文件”:setup.pysetup.cfgtox.ini 等文件在大量项目里仍然存在。

迁移路径大致是这样的:

1阶段一(2016 前):setup.py + requirements.txt + MANIFEST.in + tox.ini + ...
2阶段二(2016-2020):pyproject.toml 先标准化 [build-system],同时保留 setup.py/setup.cfg
3阶段三(2020-2024):PEP 621 标准化 [project],更多构建后端和工具迁移进 pyproject.toml
4阶段四(2024-2026):pyproject.toml 成为新项目的主配置入口,但遗留文件仍大量存在
5

Ruff 的成功不只是因为配置文件,但 [tool.ruff] 这种集中式配置确实降低了 Python 项目的工具链复杂度。过去 flake8、isort、Black、mypy、pytest 往往各有配置入口,现在越来越多工具支持把配置放进 pyproject.toml[tool.*] 命名空间里。

其他采用者

项目配置文件说明
GoReleaser.goreleaser.tomlGo 项目发布自动化
Hugoconfig.toml静态网站生成器
Zolaconfig.toml静态网站生成器
Poetrypyproject.tomlPython 包管理
Ruffruff.tomlPython linter/formatter
TaploTOML 工具链(LSP、格式化、验证)

五种格式全面对比

现在进入正题:TOML、YAML、JSON、INI、HCL,到底怎么选?

总览对比

维度TOMLYAMLJSONINIHCL
创建年份201320012001~1980s2014
规范复杂度中等无统一规范中高
注释##不支持# 或 ;# 和 //
类型系统丰富最丰富基础丰富
缩进敏感
日期时间原生支持支持不支持不支持不支持

可读性排名

YAML > TOML > INI > HCL > JSON

YAML 视觉上最干净,但“看起来简单”不等于“读起来准确”——隐式类型推断是最大的隐患。TOML 结构清晰,[section] 分区直观,类型表示明确。JSON 的引号和逗号噪音太多,作为人类编辑的配置格式体验最差。

解析速度排名

JSON 通常最快,TOML/YAML/HCL 取决于实现和配置复杂度。

JSON 的语法最小,标准库实现也最成熟,所以通常是解析性能基准。TOML 比 JSON 语法更丰富,解析一般会慢一些,但配置文件通常很小,这个差距很少成为选型主因。YAML 因为语法、锚点、标签和隐式类型规则更复杂,解析和安全边界更难控制。HCL 的重点不在“最快解析”,而在表达 Terraform 这类领域配置时的结构和表达式能力。

更实际的判断是:如果你在解析 MB 级甚至 GB 级机器生成数据,选 JSON 或二进制格式;如果只是人手写的项目配置,解析性能通常不如可维护性重要。

人类可写性排名

YAML ≈ TOML > INI > HCL > JSON

YAML 写起来最“自由”,但也最容易写错。TOML 写起来有约束但可预测——主要痛点是深层嵌套时需要写很多 [section.subsection.deep] 头部。JSON 写配置文件的体验就不用说了,不能写注释这一条就够劝退了。

每种格式的典型陷阱

这部分很实用。每种格式都有自己独特的坑,踩过才知道疼。

TOML 的坑

重复定义和隐式表规则容易踩坑。 TOML 不允许同一个键重复定义,也不允许把已经定义成具体值的键再当表使用。点分隔键可以隐式创建表,但乱序写 dotted key 虽然可能合法,却会降低可读性。

内联表不可扩展。 point = { x = 1, y = 2 } 定义之后,不能再写 point.z = 3

深层嵌套冗长。 这是 TOML 最被诟病的设计问题。五层嵌套的配置写起来会变成 [a.b.c.d.e],跟 YAML 的缩进比确实不够优雅。

YAML 的坑

“挪威问题”——旧版 YAML 规则和解析器兼容行为里的经典陷阱。

1countries:
2  - NO    #  YAML 1.1 / 部分解析器中可能被解析为 false
3  - SE    # 通常是字符串 "SE"
4  - yes   #  YAML 1.1 / 部分解析器中可能被解析为 true
5  - on    #  YAML 1.1 / 部分解析器中可能被解析为 true
6

严格说,YAML 1.2 已经把布尔值收敛到更接近 JSON 的 true / false 规则;但很多工具为了兼容旧生态,仍可能保留 YAML 1.1 的隐式布尔行为。这个问题在涉及国家代码、开关名、环境变量值的配置中会突然冒出来,排查起来非常痛苦。

隐式数字解析也容易误伤。 旧规则和部分解析器可能把 12:30 当作 sexagesimal 数字处理,1.0 也可能被当作浮点数而不是字符串。凡是 ID、版本号、时间片段、国家代码这类值,在 YAML 里都建议显式加引号。

安全风险。 在 PyYAML 等库中,使用不安全 Loader 解析不可信 YAML 有反序列化风险。处理外部输入时应该使用 safe_load() 或等价的 SafeLoader;这条规则被人忘了无数次。

JSON 的坑

不支持注释。 这一条就让 JSON 在配置文件场景中极不实用,直接催生了 JSONC 和 JSON5 等超集格式。

尾随逗号禁止。 { "a": 1, "b": 2, } 是语法错误。改配置时加了一行就忘了删逗号,这种低级错误每个人至少犯过 3 次。

不支持真正的多行字符串。 长文本只能写成一行或用 \n 转义,可读性会明显变差。

INI 的坑

无标准规范。 Python 的 configparser、PHP 的 parse_ini_file、Windows 的 GetPrivateProfileString 行为各不相同。同一份 INI 文件在不同环境下可能解析出不同的结果。

无类型系统。 所有值都是字符串,需要应用层自己做类型转换。

选型建议:一张决策图

1你的配置文件用途是什么?
2
3├─ 数据交换/API 通信  JSON(默认选择)
4
5├─ 基础设施即代码(Terraform)→ HCL
6
7├─ DevOps/CI/CD/Kubernetes  YAML(生态强制要求时遵循工具)
8
9├─ 应用/项目配置文件
10  ├─ 新项目自由选择  TOML
11  ├─ 已有工具链要求  遵循工具要求
12  └─ 极简配置(几个键值对)→ TOML  INI
13
14└─ 需要编程逻辑(循环、条件)→ HCL 或考虑 DSL
15

业界趋势

最后聊聊配置格式的发展方向。

TOML 持续崛起

TOML 正在经历“慢热式”的广泛采用。不是爆发式增长,而是由一个个具体的技术决策推动:Rust 生态的示范效应、Python 包装生态对 pyproject.toml 的持续标准化、以及 Ruff、Poetry、Hatch、uv 等工具的采用,都在扩大 TOML 的日常可见度。编辑器工具链也成熟了——Taplo(TOML LSP)提供自动补全、验证、格式化,开发体验已经比较完整。

“YAML 疲劳”蔓延

DevOps 和云原生社区对 YAML 的不满正在积累。Kubernetes 生态里已经出现了 CDK8s、Pulumi 等用真正编程语言生成配置的替代方案。复杂 YAML 模板(如 Helm Charts)的可维护性问题日益突出。

但 YAML 的生态惯性极强——Kubernetes、GitHub Actions、GitLab CI 等核心工具仍然强制使用 YAML,短期内不会改变。

JSON 超集兴起

JSON 不支持注释这个根本缺陷,催生了 JSONC(VS Code 配置广泛使用)和 JSON5(更宽松的语法)等超集。在 TypeScript 和前端工具生态中,这类“类 JSON 配置”已经很常见。

配置即代码

一个更深层的趋势:当配置复杂到一定程度时,静态的声明式格式都不够用,需要编程语言的抽象能力。Pulumi 用 TypeScript/Python/Go 定义基础设施,AWS CDK 用编程语言生成 CloudFormation 配置,Dhall 和 CUE 是专门设计的可编程配置语言。

写在最后

回头看看这五种配置格式,有一个感受很深:没有完美的配置格式,只有最适合场景的选择。

JSON 是数据交换的通用语言,但不是好的配置格式。YAML 是 DevOps 领域的事实标准,但设计缺陷正在累积技术债。INI 是历史遗留的极简格式,新项目不建议使用。HCL 是基础设施即代码的专用工具,不适用于通用场景。

而 TOML 的设计哲学——“语义明显、最小化、无歧义”——在配置文件领域代表了最健康的平衡点。它没有 INI 的功能贫乏,没有 YAML 的过度工程,也没有 JSON 的注释缺失。

对于新项目,如果你要的是“人手写、机器解析、结构不太复杂”的应用配置,TOML 是 2026 年我会默认推荐的选择。这不是跟风,而是算过账的。

参考来源


TOML 深度调研:对比 YAML、JSON 等五大配置格式,哪种最适合你的项目?》 是转载文章,点击查看原文


相关推荐


如何将SVG格式文件转为PDF? 方便打印输出、正式汇报、跨平台展示
诸葛大钢铁2026/4/26

在日常设计、开发与文档交付过程中,SVG转PDF是一个非常高频但容易被忽视的需求。很多人一开始会觉得“只是格式转换而已”,但真正遇到输出打印、正式汇报或跨平台展示时才发现:SVG在不同设备上的兼容性并不总是稳定,而PDF才是更通用、更专业的交付格式。 尤其是在以下场景中,这个需求会变得非常明显: 设计稿需要提交评审或印刷 网页图标或流程图需要归档成标准文件 跨平台传输时避免样式错乱 因此,一个稳定、清晰、无损的SVG转PDF方案就显得非常重要。 一、设计软件直接导出


《swiftUI进阶 第9章SwiftUI 状态管理完全指南》
90后晨仔2026/4/18

概述 状态管理是 SwiftUI 应用的核心。本章将系统介绍从 iOS 13 到 iOS 17+ 的所有状态管理技术,包括传统的 ObservableObject 系列和现代的 @Observable 宏,帮助你根据项目需求选择最合适的方案。 第一部分:基础状态管理(iOS 13+) 1. @State:本地视图状态 @State 用于管理视图内部的简单状态,当值改变时自动刷新 UI。 struct CounterView: View { @State private var coun


Nginx 从入门到精通:全面解析与实战指南
程序员果子2026/4/10

目录 前言:为什么要学 Nginx? 一、Nginx 基础入门:从零搭建第一个服务 1.1 初识 Nginx:它是什么,能做什么? 1.2 第一个 Nginx 服务:最小化配置实战 1.3 安装:Linux 里的 Nginx 魔法:从下载到部署,轻松拿捏! 二、核心架构与配置解析:读懂 Nginx 的 "运行逻辑" 2.1 架构精髓:Master-Worker 进程模型 2.2 配置骨架:从 http 到 location 的层级关系 2.3 静态资源服务:Nginx 的 "原


多Agent工作流开发
字节逆旅2026/4/2

最近 OpenClaw、Claude Code 特别火,我当时就在想,能不能写个自己的Agent,让它自动根据我的需求文件干活?比如我改个 tasks.md,它就自动跳出来把代码写了。这不比怼着ide开发高级多了? 最开始的想法非常简单粗暴:用 Node.js 写个脚本,利用 chokidar 盯着一个 todo 文件夹。只要文件一变,脚本就通过 child_process 里的 exec 去调 claude 命令。 初版脚本核心逻辑: const chokidar = require('cho


利用 Cloudflare 邮件路由实现无限子邮箱配置指南
墨风如雪2026/3/24

上几期文章我介绍了怎么把域名托管到CLoudFlare和免费白嫖CF CDN的操作,这次我演示的是我日常最喜欢的功能之一,邮箱路由功能。可以只需要一个域名就可以拥有属于自己的邮箱,而且可以创建无限的子邮箱提供使用。 在这里你不需要搭建复杂的邮局,只要你有一个托管在 Cloudflare 的域名,就可以用任意的前缀邮箱来注册你想要的账号,所有邮件都会自动转发到你指定的主邮箱里面,接收验证码会非常的方便。 强大的开源资源库 在正式配置之前,我这里先介绍一个收集了十分多使用CLoudFlare免费资源


告别登录中断:前端双 Token无感刷新
发现一只大呆瓜2026/3/16

前言 在前后端分离的项目中,为了安全,Token 通常会设置有效期。但如果 Token 过期时强制用户重新登录,会极大地破坏用户体验。如何做到在用户毫无察觉的情况下,自动完成 Token 的续期?本文将深度拆解 “双 Token 无感刷新” 的实现机制。 一、 为什么需要“无感刷新”? 举个简单例子,你正在某 App 编辑内容,中途切出几分钟,再切回来时,直接弹出登录页,提示“登录已过期,请重新登录”,这种场景很容易让用户流失。 传统的单 Token 方案存在一个两难境地: 有效期过短:用户操


构建无障碍组件之Switch Pattern
anOnion2026/3/8

Switch Pattern 详解:构建无障碍开关组件 开关(Switch)是一种模拟物理开关的控件,用于在两个状态(通常是"开"和"关")之间切换。在一些 UI 组件库中,它也被称为 Toggle(切换开关)。本文基于 W3C WAI-ARIA Switch Pattern 规范,详解如何构建无障碍的开关组件。 一、Switch 的定义与核心概念 1.1 什么是 Switch Switch 是一种特殊的二元状态控件,它: 模拟物理开关的行为 在两个互斥状态之间切换(开/关、启用/禁用) 与


纯 CSS 实现弹性文字效果
掘金安东尼2026/2/28

原文:How to Create a CSS-only Elastic Text Effect 翻译:TUARAN 欢迎关注 前端周刊,每周更新国外论坛的前端热门文章,紧跟时事,掌握前端技术动态。 每个字母单独动画的文字效果总是很酷、很吸睛。这类错峰动画通常依赖 JavaScript 库实现,对我们要实现的这种相对轻量的设计效果来说,代码往往偏重。本文将探索只用 CSS、无需 JavaScript 实现 fancy 文字效果的技巧(意味着需要手动拆分字符)。 截至撰写时,仅 Chrome 和


LiteOps:轻量级CI/CD平台,重塑开发运维新体验
YL_jia2026/2/19

LiteOps:轻量级CI/CD平台,重塑开发运维新体验 在效率至上的时代,LiteOps正以“简洁易用”和“开箱即用”的理念,重新定义自动化部署流程。 一、LiteOps:为何成为开发运维的新宠? 在软件开发的快速迭代中,持续集成和持续部署(CI/CD) 已成为提升开发效率和软件质量的关键手段。 然而传统CI/CD工具往往配置复杂、学习曲线陡峭。LiteOps作为一个专注于实用性的轻量级CI/CD平台,应运而生,它开源免费,能够为开发团队提供高效、便捷的自动化构建和部署解决方案。 1.1


BLE协议栈:链路层与ATT/L2CAP的交互详解
mftang2026/2/11

目录 概述 1  整体交互架构概览 1.1 交互流程总览 1.2 数据平面:PDU传输流程 1.2.1  发送路径:从ATT到空中 1.2.2 接收路径:从空中到ATT 1.3 控制平面:连接与参数管理 1.3.1 连接生命周期交互 1.3.2 关键参数协商流程 1.4 事件与通知机制 1.4.1 链路层事件驱动模型 1.4.2  ATT通知/指示与链路层交互 1.5 性能优化交互 1.5.1 数据长度扩展交互(BLE 4.2+) 1.5.2 信道选择算法 1

首页编辑器站点地图

本站内容在 CC BY-SA 4.0 协议下发布

Copyright © 2026 XYZ博客