D2 入门
D2 是声明式绘图语言,用 Go 编写,配合命令行工具,从纯文本生成 SVG/PNG 格式的图片,支持 UML 类图、时序图、网格图、SQL 数据表、代码、图片和图表等元素。生成出来的图片效果在同类工具中算出众的(对比 PlantUML),由于 PlantUML 生成的图片风格不统一且运行在 Java 虚拟机上(谁家命令行工具用 .jar 运行啊……),权衡之后选择了图片类型更少但效果更好的 D2。尽管没有完全实现 UML 而且不支持用例图,但似乎也能用自定义元素实现类似的效果。
安装 D2
官方提供的方法是:
curl -fsSL https://d2lang.com/install.sh | sh -s --
在 macOS 上可以使用 Homebrew 安装:
brew install d2
命令行
d2 input.d2 out.svg
加上 -w 或 --watch Flag,可以监听 input.d2 变化,打开浏览器实时更新查看变更。
d2 -w input.d2 out.svg
输出格式支持 .png,修改拓展名即可。
基本语法
D2 主要有三个概念:形状(Shapes)、连接(Connections)和容器(Containers)。
x -> y: Hello World
以上语句定义了两个形状之间的连接,并添加了名为「Hello World」的标签(label)
定义形状
以下都是合法名称:
imAShape
im_a_shape
im a shape
i'm a shape
# 一个连字符 - 不代表连接,-- 表示一个连接
# 所以 a--shape 代表的是 a 与 shape 的连接
a-shape
用冒号定义形状的标签,也就是显示名称:
pg: PostgreSQL
可以这样更改形状。
pg.shape: cloud
所有形状见官方文档。
对于 circle 和 square 两个形状,如果手动设置宽高,它们会保持相同的 1:1 比例,不会因此变成 oval 和 rectangle。
定义连接
连接有四种,含义是不言自明的:
---><-<->
连接也可以有标签:
Shape 1 -- Shape 2: Label
连接可以重复,不会覆盖,而是同时存在:
Database -> S3: backup
Database -> S3
Database -> S3: backup
连接可以多个写在同一行(chaning),标签会同时应用于所有连接:
High Mem Instance -> EC2 <- High CPU Instance: Hosted By
连接可以定义箭头前后的样式和标签,下图的箭头来源处显示 1,目标处显示 *(一对多),并且目标处的箭头显示为菱形。
a -> b: To err is human, to moo bovine {
source-arrowhead: 1
target-arrowhead: * {
shape: diamond
}
}
可以在别处引用某个连接:
x -> y: hi
x -> y: hello
(x -> y)[0].style.stroke: red
(x -> y)[1].style.stroke: blue
定义容器
在一个形状内再定义一个形状,父形状就成为容器。
im a parent.im a child
也可以使用嵌套语法:
clouds: {
aws: {
load_balancer -> api
api -> db
}
gcloud: {
auth -> db
}
gcloud -> aws
}
关于花括号
a.b 的写法和 a { b: } 应该是等价的,比如下面两个语句是等价的:
Shape 1.shape = cloud
Shape 1: {
shape = cloud
}
尽管文档中所有例子都要求有 :,但实际测试后发现可以删除,以下语句是合法的:
Shape 1 {
shape = cloud
}
除非需要添加标签文本。
Shape 1: Label {
shape = cloud
}
特殊对象
文本
这样插入 Markdown 作为形状:
explanation: |md
# I can do headers
- lists
- lists
And other normal markdown stuff
|
还可以是 LaTex:
formula: |latex
\lim_{h \rightarrow 0 } \frac{f(x+h)-f(x)}{h}
|
代码也可以,标注语言即可,以下是 Go 的例子:
explanation: |go
awsSession := From(c.Request.Context())
client := s3.New(awsSession)
ctx, cancelFn := context.WithTimeout(c.Request.Context(), AWS_TIMEOUT)
defer cancelFn()
|
所以,只要记住插入文本的语法是前后标上 |,在第一个 | 之后标注语言即可,如果语言是 Markdown 或 LaTex,就会被解析。
如果嵌入的代码中也用到了 | 甚至 ||,就可以把 | 替换为 || 或 |||。
my_code: |||ts
declare function getSmallPet(): Fish | Bird;
const works = (a > 1) || (b < 2)
|||
图片和图标
给形状添加 icon 属性即可。
backup: {
icon: https://icons.terrastruct.com/aws%2FStorage%2FAWS-Backup.svg
}
如果想显示为独立的图片,将形状设置为 image
backup: {
icon: https://icons.terrastruct.com/aws%2FStorage%2FAWS-Backup.svg
shape: image
}
SQL 表格
objects: {
shape: sql_table
id: int {constraint: primary_key}
disk: int {constraint: foreign_key}
json: jsonb {constraint: unique}
last_updated: timestamp with time zone
}
disks: {
shape: sql_table
id: int {constraint: primary_key}
}
objects.disk -> disks.id
UML 类图
D2 Parser: {
shape: class
# Default visibility is + so no need to specify.
+reader: io.RuneReader
readerPos: d2ast.Position
# Private field.
-lookahead: "[]rune"
# Protected field.
# We have to escape the # to prevent the line from being parsed as a comment.
\#lookaheadPos: d2ast.Position
+peek(): (r rune, eof bool)
rewind()
commit()
\#peekn(n int): (s string, eof bool)
}
UML 时序图
Office chatter: {
shape: sequence_diagram
alice: Alice
bob: Bobby
awkward small talk: {
alice -> bob: uhm, hi
bob -> alice: oh, hello
icebreaker attempt: {
alice -> bob: what did you have for lunch?
}
unfortunate outcome: {
bob -> alice: that's personal
}
}
}
网格图
见文档。
UML 用例图
D2 不直接支持用例图,但有一个形状是 person,可以用来代表用户,应该可以这样实现用例图:
user.shape = person
user -> Use Case 1
user -> Use Case 2
user -> Use Case 3
Use Case 4 <- Use Case 3: extends
2026-03-12