一、TOML 是什么?
TOML(Tom's Obvious, Minimal Language)是一种为人类阅读优化的配置文件格式。它的设计目标只有一句话:写起来像 INI 一样直观,读起来比 JSON 更友好,结构上比 YAML 更不容易踩坑。 如果你写过 Rust 的 Cargo.toml、Python 的 pyproject.toml、Hugo 的 config.toml,那么你已经在用它了。近几年 TOML 几乎成为新一代工具链的"事实标准配置格式"。
JSON、YAML、INI 都有一定的缺点,TOML 在这三者之间找到了平衡点:规则少、类型明确、对人友好、对机器无歧义。
| JSON | |
| YAML | |
| INI |

二、文件基本约定
• 文件后缀: .toml• 编码:必须是 UTF-8 • 大小写敏感 • 行尾换行符 LF ( \n) 或 CRLF (\r\n) 都允许• 空白与缩进无意义(这是和 YAML 最大的区别) • 注释以 #开头,可写在行首或行尾
# 这是一行注释title = "TOML 示例"# 行尾注释也允许三、键值对(Key/Value)
TOML 的最小单位是键值对:
key = "value"规则:
1. 一行只能写一个键值对 2. 等号两侧的空格可有可无 3. 值必须是合法的 TOML 类型(下文详述) 4. 每个键必须有值——没有"裸键"或"空值"这种概念
3.1 键名(Keys)的三种写法
# 1. 裸键(Bare Key):只允许 A-Z a-z 0-9 _ -name = "Alice"user_id = 42api-key = "xxx"# 2. 字符串键(Quoted Key):用 " 或 ' 包起来,可以包含任意字符"127.0.0.1" = "localhost""中文键" = "也合法"'literal key' = "原样字符串作键名"# 3. 点分键(Dotted Key):用 . 创建嵌套结构,等价于嵌套表server.host = "localhost"server.port = 8080# 等价于:# [server]# host = "localhost"# port = 8080⚠️ 注意:同一个键不能在同一作用域里被重复定义,否则解析器报错。
四、字符串(String)
TOML 提供 4 种字符串,对应"是否多行"和"是否转义"两个维度:
| 基本(支持转义) | "..." | """...""" |
| 字面量(原样) | '...' | '''...''' |
4.1 基本字符串
用双引号包围,支持常见转义字符:
greeting = "Hello\tWorld\n"path = "C:\\Users\\Alice"emoji = "❤"# ❤支持的转义序列:\b \t \n \f \r \" \\ \uXXXX \UXXXXXXXX。
4.2 多行基本字符串
description = """这是一段多行文本,开头的换行会被自动去掉。\反斜杠+换行可以续行,\所以这一段最终是一行。"""4.3 字面量字符串(推荐写正则、Windows 路径)
用单引号,不解释任何转义:
regex = '\d{3}-\d{4}'# 不需要写成 '\\d{3}-\\d{4}'windows_path = 'C:\Users\Alice'# 反斜杠原样保留4.4 多行字面量字符串
sql = '''SELECT *FROM usersWHERE name = 'Alice''''五、数字与布尔
5.1 整数(Integer)
int1 = 99int2 = -17int3 = +42int4 = 1_000_000# 下划线分隔,提升可读性hex = 0xDEADBEEFoct = 0o755bin = 0b110101105.2 浮点数(Float)
flt1 = 3.14flt2 = -0.001flt3 = 1e10flt4 = 6.626e-34flt5 = 1_000.123_456# 同样支持下划线分隔# 特殊值inf = infninf = -infnan = nan5.3 布尔(Boolean)
只有两个值,必须小写:
enabled = truedebug = false六、日期与时间
TOML 是少数原生支持日期类型的配置格式,遵循 RFC 3339:
# 1. 带时区的日期时间(Offset Date-Time)dt1 = 2026-05-08T14:30:00+08:00dt2 = 2026-05-08T06:30:00Z # Z 表示 UTC# 2. 本地日期时间(Local Date-Time, 不带时区)dt3 = 2026-05-08T14:30:00# 3. 仅日期(Local Date)d = 2026-05-08# 4. 仅时间(Local Time)t = 14:30:00.123不需要任何引号包围——这是 TOML 与 JSON/YAML 最显著的差异之一。
七、数组(Array)
数组用方括号 [],元素间逗号分隔:
ports = [80, 443, 8080]hosts = ["alpha", "beta", "gamma"]mixed_ok = [1, 2, 3] # 推荐:同质类型mixed_too = [1, "two", 3.0, true] # 也允许:TOML 1.0 起放宽了限制# 多行数组,允许尾随逗号contributors = ["Alice <alice@example.com>","Bob <bob@example.com>","Carol <carol@example.com>", # 尾随逗号合法]# 嵌套数组matrix = [[1, 2], [3, 4], [5, 6]]八、表(Table):TOML 的灵魂
表(Table) 就是其他语言里的对象、字典、Map。它是 TOML 表达嵌套结构的核心机制。
8.1 标准表
用 [表名] 声明,之后所有键值对都属于这个表,直到下一个表头出现:
title = "全局键放在最前面"[database]host = "localhost"port = 5432user = "admin"[server]bind = "0.0.0.0"port = 8080等价于 JSON:
{"title":"全局键放在最前面","database":{"host":"localhost","port":5432,"user":"admin"},"server":{"bind":"0.0.0.0","port":8080}}💡 最佳实践:所有"裸键值对"都写在文件最顶部,表头之后的内容全部归属对应表。如果把全局键写在表头下面,会被错误地划进那个表。
8.2 嵌套表(点分表名)
[servers.alpha]ip = "10.0.0.1"role = "frontend"[servers.beta]ip = "10.0.0.2"role = "backend"等价于:
{"servers":{"alpha":{"ip":"10.0.0.1","role":"frontend"},"beta":{"ip":"10.0.0.2","role":"backend"}}}8.3 内联表(Inline Table)
适合短小、扁平的对象,类似 JSON 风格:
point = { x = 1, y = 2 }person = { name = "Alice", age = 30 }# 内联表必须写在一行内,不能跨行,且一旦写完就"封闭"——# 不能再用 person.email = "..." 往里面追加键等价于:
{"point":{"x":1,"y":2},"person":{"name":"Alice","age":30}}九、表数组(Array of Tables)
要表达"一组同构对象"(比如多个用户、多个依赖、多个产品),用双方括号[[...]]:
[[products]]name = "Hammer"sku = 738594937[[products]]name = "Nail"sku = 284758393color = "gray"[[products]]name = "Saw"sku = 192847465等价于:
{"products":[{"name":"Hammer","sku":738594937},{"name":"Nail","sku":284758393,"color":"gray"},{"name":"Saw","sku":192847465}]}每出现一次 [[products]],就向 products 数组里追加一个新元素。
表数组里的子表
[[users]]name = "Alice"[users.address]city = "Beijing"zip = "100000"[[users]]name = "Bob"[users.address]city = "Shanghai"zip = "200000"等价于:
{"users":[{"name":"Alice","address":{"city":"Beijing","zip":"100000"}},{"name":"Bob","address":{"city":"Shanghai","zip":"200000"}}]}子表的缩进仅为可读性,TOML 不要求缩进。但子表头必须写在对应的
[[users]]之后、下一个[[users]]之前,否则归属会错。
十、一份"贴近实战"的完整示例
# ===========================# myapp.toml — 应用配置示例# ===========================title = "MyApp"version = "1.2.0"[owner]name = "Alice Wang"dob = 1990-07-15T09:00:00+08:00[database]host = "127.0.0.1"port = 5432connection_max = 100enabled = trueallowed_ips = ["10.0.0.1", "10.0.0.2", "10.0.0.3"][database.credentials]user = "admin"password = "s3cret"[logging]level = "info"outputs = ["stdout", "file"]file = { path = "/var/log/myapp.log", max_size_mb = 100 }[[features]]name = "dark-mode"enabled = true[[features]]name = "beta-search"enabled = falserollout = 0.05[[servers]]name = "alpha"ip = "10.0.0.1"[[servers]]name = "beta"ip = "10.0.0.2"十一、容易踩的 5 个坑
1. 全局键被误归到表里
[server]host = "localhost"title = "MyApp"# ❌ 这个 title 会被解析成 server.title✅ 修复:把全局键移到所有表头之上。
2. 重复定义同一张表
[server]host = "a"[server]# ❌ 报错:server 被定义两次host = "b"✅ TOML 禁止重复定义同名标准表。如果想要多个,用 [[...]] 表数组。
3. 内联表不可"事后追加"
point = { x = 1, y = 2 }point.z = 3# ❌ 报错:内联表声明后即封闭✅ 修复:要么写完整 { x = 1, y = 2, z = 3 },要么改用标准表 [point]。
4. 字符串混淆
path = "C:\Users\Alice"# ❌ \U 会被当作 Unicode 转义,通常报错✅ 修复:用字面量字符串 'C:\Users\Alice',或转义 "C:\\Users\\Alice"。
5. 日期不要加引号
created = "2026-05-08"# ⚠️ 这是字符串,不是日期created = 2026-05-08# ✅ 这才是 TOML 的 Local Date 类型如果下游程序按"日期"类型读取,引号版本会拿到字符串,导致类型错误。
十二、TOML vs JSON vs YAML 速查
# | # | ||
1_000_000 | |||
经验法则:机器之间传数据用 JSON;人写配置用 TOML;只有当你确实需要锚点、引用、复杂结构时才用 YAML。
十三、各语言的 TOML 库
| Rust | toml crate |
| Python | tomllib(只读);写入用 tomli-w 或 tomlkit |
| Go | github.com/BurntSushi/tomlgithub.com/pelletier/go-toml/v2 |
| Node.js / TypeScript | @iarna/tomlsmol-toml |
| Java | tomlj |
| C/C++ | tomlplusplus |
完整列表见官方维护的清单:https://github.com/toml-lang/toml/wiki。
十四、写在最后
TOML 的设计哲学可以浓缩成一句话:
最少的规则、最明确的类型、最不挑剔的人。
它不会取代 JSON 在数据交换里的位置,也不会取代 YAML 在 Kubernetes、Ansible 里的生态。但只要你在写"人会反复打开来手动改的配置文件",TOML 几乎都是更省心的那个选择。
下次新建 config.json 之前,不妨先想想:要不要换成 config.toml?
小米招聘内推
交个朋友,进AI交流群

每天分享最新 小米AI 内部培训资料
关注公众号-私信回复:
ai资料:获取AI完整资料包
全家桶:获取激活码
小龙虾:获取安装教程
md:获取激活码
关注公众号
夜雨聆风