Workflow、Node、Connection、Execution:四个词讲清 n8n 的世界
画布上是五个方块、四条线。把这东西导出成 JSON,只剩两个键:nodes 和 connections。执行记录在另一个地方,一条一条排着,每条带个编号。
三处说的是同一件事,用四个词:workflow、node、connection、execution。这四个词理清了,后面读任何节点教程都省力;理不清,你会一直在「我明明点了执行」和「它为什么没跑」之间来回撞。
不用会写代码。装好的 n8n 能打开、跑过一次工作流就够(没装看这篇,界面还不熟的先翻界面导览)。我这台是 2.43.7,你那边小版本不同,按钮位置可能差一点。
四个词,四样东西
先摆一张对照表,后面几节都是把它拆开讲。
| 词 | 它是什么 | 存在哪 | 数量关系 |
|---|---|---|---|
| Workflow | 一组节点连起来干一件事 | 数据库里的工作流表,一份 JSON | 1 个工作流有 N 个节点 |
| Node | 一个执行单元,干一步活 | 工作流 JSON 的 nodes 数组里 | 1 个节点属于 1 个工作流 |
| Connection | 把上一个节点的输出接到下一个的输入 | 同一个 JSON 的 connections 对象里 | 1 个工作流有 N 条线 |
| Execution | 这个工作流被跑了一次 | 执行表,独立于工作流 | 1 个工作流有 N 条执行 |
最容易混的是最后一行。工作流是图纸,执行是施工。图纸改十遍,之前施的工不会跟着变。

Workflow:一个容器,外加两个状态
官方给的定义很短:一组连起来自动完成某件事的节点;触发器响了、你手点了、别的流程调它了,它就开始跑,按节点一个个执行,可以分叉、合并、循环。
定义没什么可挑的。真正要留神的是 2.x 之后多出来的那个状态:草稿和已发布是两回事。
你在画布上改东西,n8n 自己存,一秒到五秒之内落库,没有保存按钮。但这只是存进草稿。想让改动上线,得点右上角那个「发布」,把某一个版本钉到生产上。之后定时器、Webhook、应用事件跑的都是那个钉住的版本,不是你现在屏幕上这版。
这条规矩解决了一个老问题(改到一半被定时任务撞上),也造了一个新坑:参数改完忘了发布,线上跑的还是昨天那套逻辑,而画布上看着一切正常。我第一次遇到时盯着两版参数比了十分钟,才想起上面那按钮还是亮的。

这也顺便解释了为什么有些人的第一个工作流死活「激活」不了。只有一个手动触发器,它天生没有生产形态,发布按钮永远灰着。要定时,加 Schedule Trigger;要接外部请求,加 Webhook。有了这类触发器,按钮才会亮。
从接口看更清楚:我这台实例上,新建的工作流 active 是 false,activeVersionId 是 null,只有一个 versionId 在跟着每次改动变。没发布过,就没有线上版本。
Node:名字才是主键
节点是一个执行单元。有的负责开局(触发器),有的取数据、发数据、算数据,有的只做流程控制,一行 IF 也能是一个节点。
落到 JSON 里,一个节点就七样东西:
{
"parameters": { "jsCode": "return [{ json: { amount: 620 } }];" },
"id": "n2",
"name": "造两条订单",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [-400, 0]
}type:它是哪种节点。n8n-nodes-base.code就是 Code 节点,-base.后面那截是节点名的小写。typeVersion:节点定义的版本。同一个节点的不同版本,参数结构会变。我这份里 IF 是2.2、Edit Fields 是3.5、Code 是2、Manual Trigger 是1。这数字不是你填的,是它创建时按当时的定义写进去的。parameters:你在右边面板里填的一切都在这里。换节点类型,这块整个换掉。position:画布坐标,纯显示用,跟执行顺序无关。id:工作流内部用的短标识,复制节点会生成新的。
name 看着最不起眼,实际是这四个词里最容易吃亏的一处:它是主键。连接记的是名字,不是 id。
我在画布上把「小单归档」改成「小单归档(改)」,四条连线一条没断,保存后接口里的 connections 也跟着变成了新名字——这是界面替你补的。换个方式,直接改 JSON 里的 name、连接不动,服务端会当场拒绝,报错还一次报两条:
Workflow structure is invalid. nodes[4].name (duplicate_node_name):
Duplicate node name "大单跟进"; connections.判断大单.main[1][0].node
(unknown_connection_target): Connection target "小单归档" does not
reference an existing node第一句说重名,第二句说有条线指着一个不存在的节点。两句其实是一件事的两面:你把一个节点改成了别人的名字,而被顶掉的那个名字,连接还在指着它。
所以节点名我建议当变量名来起:别用「Set」「Code 1」这种,也别隔两天改一次。名字里带空格、括号、中文都行,n8n 认,但你自己在表达式里写 $('小单归档(改)') 的时候容易漏个括号。
Connection:两层数组,第一层是出口序号
连接是把一个节点的输出接到另一个节点的输入。JSON 里长这样:
"connections": {
"造两条订单": { "main": [[{ "node": "判断大单", "type": "main", "index": 0 }]] },
"判断大单": { "main": [
[{ "node": "大单跟进", "type": "main", "index": 0 }],
[{ "node": "小单归档", "type": "main", "index": 0 }]
]}
}拆开读:最外层键是源节点名;main 是连接类型(普通数据流;AI 那套是 ai_tool、ai_languageModel 这些);里面那层数组的下标就是第几个出口;再里面是目标列表,一个出口可以连好几个下游。
判断大单有两组,所以它是 [,]。第一组对应节点上那个标 true 的圆点,第二组对应 false。粗看会以为数组套多了,其实就是「第几个出口 → 连到谁」。

这里有个概念上的误会值得掰开。很多人以为 IF 是「二选一」:条件成立走这边,不成立走那边,只走一条。
不是。IF 是按条分流。我让它收两条订单,620 和 180,结果是 true 分支 1 项、false 分支 1 项,两条线都亮了。你要是拿 100 条数据进去,它按每条自己的金额分到两边,可能左边 30 条右边 70 条,也可能一边 0 条。
所以「IF 后面的节点没执行」这句话,先确认是不是那一侧压根没数据。这不是故障。
Execution:一次运行,带一份快照
执行是这个工作流被跑了一次。手动点一次算一次,定时器响一次算一次,Webhook 来一个请求算一次。它不属于工作流 JSON,存在另一张表里,靠 workflowId 挂回去。
一条执行记录里我关心的字段:
| 字段 | 这条记录里的值 | 有什么用 |
|---|---|---|
id | 35 | 全实例一条自增序列,不是每个工作流从 1 开始 |
workflowId | 9biNEw9D0DqWOVV1 | 它属于哪个工作流 |
mode | manual | 手动跑的还是生产跑的 |
status | success | 成功、失败、取消、崩溃、等待中 |
startedAt / stoppedAt | 01:17:42.352 / 01:17:42.513 | 差 161 毫秒,就是界面上那个「在 161毫秒 内」 |
workflowVersionId | 一个 uuid | 这次跑的是哪个版本 |
最后一行容易忽略但很有用:执行认的是版本。你改完参数没发布,生产跑的还是旧版本,执行记录里挂的就是旧版本的 id。

还有一个我这次才注意到的细节:每条执行里存了一份当时的工作流的快照(workflowData)。我把「小单归档」改成「小单归档(改)」之后,回去翻 09:17:42 那条执行,画布上显示的仍然是「小单归档」——因为渲染用的是那条执行自带的快照,不是你现在的画布。
这解释了两件事。好的一面:改参数、删节点,旧记录不会被篡改,回头查问题看到的就是当时的现场。坏的一面:你拿旧记录去对照现在的画布,节点名可能对不上,别以为是自己记错了。

存多久是个现实问题。默认开自动清理:超过 336 小时(14 天)的删掉,总量超过 10000 条也从旧的开始删。成功和失败都存,手动跑的也存。两条规矩谁先撞上算谁:每 5 分钟跑一次的工作流,一天 288 次,14 天攒到 4032 条,先撞年龄;一天 2000 次的,第五天就满一万,先撞条数。所以「执行列表里没有那次」,不一定是没跑,可能已经被清掉了。
串起来看:一次排错的顺序
四个词分开都懂,用起来还得有个顺序。我的习惯是从外往里收:
- 先看执行记录的状态。没有记录,说明压根没触发——问题在触发器或发布状态,不在节点里。
- 状态是失败,点进去看哪个节点红着。节点详情里看输入,多数时候输入就已经不对了。
- 状态成功但结果不对,看连线上的项目数。某条线是 0,后面的节点当然什么都不干。
- 数字对但字段不对,才轮到怀疑节点参数,或者上游把类型改了。
这个顺序的好处是每一步都能否掉一大片可能。反过来,一上来就盯着 Code 节点看代码,往往看半小时才发现是上游只发了 0 条。
怎么算真看懂了
不用背定义,做三件事就够了,每件都有可观察的结果。
一、数一数。画布上有几个方块,导出的 JSON 里 nodes 数组就该有几个。我这份是 5 个,数组长度 5。连线条数也一样,4 条线对应 connections 里 4 个源键(判断大单一个键里装了两组,但仍是 4 条线)。
二、改条线。把 false 那一路的节点删掉,再导出,判断大单 的第二组数组应该变成空数组,而不是整组消失。这一步能让你记住「出口是位置决定的,不是有没有下游决定的」。
三、跑两次。跑完去「所有执行」,应该多一条,ID 比上一条大 1,时间是你点下去的那一刻。再改一个参数、不发布,跑一次,然后去线上(定时或 Webhook)看它用的还是旧参数——如果这是你的真实业务,这一步建议在测试工作流上做。
五个真会撞上的错
1. 两个节点同名。复制节点后忘了改名,或者手工改 JSON。保存时服务端拒绝,报 Duplicate node name,并且同时甩一条 unknown_connection_target。看到两条别慌,改回唯一的名字就好。
2. 改了节点名,表达式没跟着改。连接会被界面自动补,表达式不会。上一个节点叫 A,你在下游用 $('A').item.json.amount 取数,改名成 B 之后这句就找不到东西了,报错指向表达式那一行,而不是改名这件事。
3. 发布按钮是灰的。工作流里只有手动触发器,没有能上线的东西。鼠标停上去会写「此工作流没有需要发布的触发节点」。加个 Schedule Trigger 或 Webhook 才有得发。
4. 改完参数,定时任务跑的还是旧逻辑。改的是草稿,没点发布。这类问题最难查,因为画布、参数、测试执行全都正常,只有线上的行为不对。
5. 执行记录找不到。三种可能:超过保留期被清理、工作流被删导致记录跟着没了、或者把「成功也存」的开关关了(EXECUTIONS_DATA_SAVE_ON_SUCCESS=none)。前两种最常见。
导出、分享、留痕的风险
工作流 JSON 是可以整份导出、发给别人的。这里有三处会漏东西。
参数里的明文。凭据本体不在 JSON 里(只留一个名字引用),但 parameters 里什么都可能有:URL 上带的 token、HTTP 请求头里手写的 key、Webhook 的 path。grep 一遍 key、token、Bearer 再发出去,两分钟的事。
执行记录里是原始数据。节点跑过什么,记录里就存什么原文,订单号、客户名、地址都在。自托管能自己控保留期,把 EXECUTIONS_DATA_MAX_AGE 调小是最省事的做法;多人共用的实例,最好一开始就设。
别人发来的 JSON 直接粘。粘进来就是在你实例上跑他写的代码,Code 节点里的 JS 不会问你要不要执行。来源不明的工作流丢进空的测试实例,看完再说。
小结
工作流是图纸,节点是图纸上的方块,连接是方块之间的箭头,执行是照着图纸施工的那一次。四个词对应四样东西,位置不一样,改动的后果也不一样:改节点参数影响以后每一次执行,改执行记录什么都改不了(它本来就是记录),改名会让连接跟着走但表达式不一定。
真要我挑一个最该先记住的,是「执行带快照」这件事。它同时解释了为什么旧记录不会骗你、为什么新改动不一定生效、为什么清理期一过就什么都查不到。
判断自己懂没懂,有个笨办法:随便打开一个别人做的工作流,不看画布,只看导出的 JSON,能不能说出它跑起来会有几个节点、几条路、哪条是空跑。说得出来,这四个词就过关了。
接着往下
还没跑通过第一个工作流的,先看《第一个工作流:手动触发 → 编辑字段 → 代码》,那篇讲怎么把三个节点连起来跑通。启动报错、端口占用这类进不去门的问题,在这里。整门课的目录在这一页,节点相关的都在这个分类下。
参考资料
- Key concept glossary:workflow、node、execution、publish 这几个词的官方定义,本文对齐的就是这里
- Understand workflows:工作流是什么,以及创建工作流、组件、执行这四块的分卷
- Connect nodes together:连接的建立与删除,一个节点的输出接到另一个节点的输入
- Save and publish workflows:自动保存的时间范围、发布把版本钉到线上、生产执行用已发布版本
- Understand executions:手动与生产执行的区别,哪些执行计入配额
- If:条件的数据类型与比较方式,两个输出
- Executions 环境变量:保留 336 小时、上限 10000 条、成功与失败都存这些默认值
最后更新:2026 年 11 月 4 日,用的是 n8n 2.43.7。