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

所有形状见官方文档

对于 circlesquare 两个形状,如果手动设置宽高,它们会保持相同的 1:1 比例,不会因此变成 ovalrectangle

定义连接

连接有四种,含义是不言自明的:

连接也可以有标签:

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