n8n-connections

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

n8n Connections

n8n 连接

n8n's SDK has a small connection grammar. Two of its shapes silently produce broken workflows that pass validation. This skill is mostly about not falling into those traps.
n8n的SDK包含一套简洁的连接语法。其中两种写法会生成能通过验证但实际运行异常的工作流。本技能主要讲解如何避开这些陷阱。

The non-negotiable: the
.to()
trap

不可妥协的规则:
.to()
陷阱

.to()
must go inside
.add()
, not after.
ts
.add(node.output(0)).to(target)      // ❌ connection silently dropped
.add(node.output(0).to(target))      // ✅
validate_workflow
does not catch this. The workflow validates, publishes, and runs without the wire. The bug looks identical to a misconfigured or "not firing" node.
If you've written
.add(...).to(...)
outside the parens, you have a bug. No exceptions.
<!-- TEMPORARY: .to()-after-.add() silent drop -->
.to()
必须放在
.add()
内部,而不是之后。
ts
.add(node.output(0)).to(target)      // ❌ 连接被静默丢弃
.add(node.output(0).to(target))      // ✅ 正确写法
validate_workflow
不会检测到这个问题。工作流会通过验证、发布并运行,但连接实际上不存在。这个bug看起来和节点配置错误或“未触发”的表现完全一致。
如果你写了
.add(...).to(...)
.to()
在括号外),那肯定存在bug,没有例外。
<!-- TEMPORARY: .to()-after-.add() silent drop -->

The universal connection pattern

通用连接模式

One shape covers IF/Switch branches, error outputs, merge inputs, and any generic multi-IO:
ts
.add(source.output(n).to(target))
  • source.output(n)
    : pick the output (0-indexed)
  • .to(target)
    : pick the target (default input 0)
  • .to(target.input(m))
    : pick a specific input on the target (0-indexed)
Call
.add()
once per wire. To fan out, repeat
.add()
.
有一种写法适用于IF/Switch分支、错误输出、Merge输入以及任何通用多IO场景:
ts
.add(source.output(n).to(target))
  • source.output(n)
    :选择输出(从0开始索引)
  • .to(target)
    :选择目标节点(默认使用输入0)
  • .to(target.input(m))
    :选择目标节点上的特定输入(从0开始索引)
每个连接调用一次
.add()
。要实现扇出,重复调用
.add()
即可。

Decision tree

决策树

Wiring a connection?
├── Linear (one source → one target, single output, single input)?
│   └── .add(source).to(target). The simple case; .to() outside is fine here
│       because there's no .output(n) selector inside .add()
├── Selector involved (.output(n) or composite handlers)?
│   └── .to() MUST go inside .add(). See "the trap" above
├── Targeting a specific input slot on a multi-input node (Merge)?
│   └── .add(source.output(n).to(target.input(m)))
│       AND check useDataOfInput. See references/MERGE_INDEX_RULES.md
├── Error branch?
│   └── .add(node.output(1).to(handler))
│       AND set onError: 'continueErrorOutput' on the node config.
│       See references/ERROR_OUTPUTS.md
└── Fan-out (one source → many targets) or fan-in (many sources → one target)?
    └── See references/FAN_OUT_FAN_IN.md
要配置连接?
├── 线性连接(一个源节点 → 一个目标节点,单输出、单输入)?
│   └── 使用.add(source).to(target)。这种简单场景下,.to()放在外面没问题
│       因为.add()内部没有.output(n)选择器
├── 涉及选择器(.output(n)或复合处理器)?
│   └── .to()必须放在.add()内部。参见上方的“陷阱”部分
├── 要定位多输入节点(如Merge)的特定输入槽?
│   └── 使用.add(source.output(n).to(target.input(m)))
│       并检查useDataOfInput配置。参见参考文档/MERGE_INDEX_RULES.md
├── 错误分支?
│   └── 使用.add(node.output(1).to(handler))
│       并在节点配置中设置onError: 'continueErrorOutput'。
│       参见参考文档/ERROR_OUTPUTS.md
└── 扇出(一个源节点 → 多个目标节点)或扇入(多个源节点 → 一个目标节点)?
    └── 参见参考文档/FAN_OUT_FAN_IN.md

Composite handlers (
.onTrue
,
.onFalse
,
.onCase
,
.onError
)

复合处理器(
.onTrue
.onFalse
.onCase
.onError

The SDK provides convenience handlers on IF, Switch, and any node with an error output:
ts
.add(ifNode.onTrue(targetA))     // same as .add(ifNode.output(0).to(targetA))
.add(ifNode.onFalse(targetB))    // same as .add(ifNode.output(1).to(targetB))
.add(sw.onCase(2, target))       // same as .add(sw.output(2).to(target))
.add(node.onError(handler))      // same as .add(node.output(1).to(handler))
These compose with
.output(n)
calls without conflict.
ts
.add(ifNode.onTrue(targetA))
.add(ifNode.output(0).to(targetB))
// Result: BOTH targetA and targetB on IF's main[0]. Composite + .output(n) merge.
The only shape to avoid is the
.add(selector).to(target)
trap above. That's always wrong, regardless of whether a composite handler ran earlier.
SDK为IF、Switch以及任何带有错误输出的节点提供了便捷处理器:
ts
.add(ifNode.onTrue(targetA))     // 等同于.add(ifNode.output(0).to(targetA))
.add(ifNode.onFalse(targetB))    // 等同于.add(ifNode.output(1).to(targetB))
.add(sw.onCase(2, target))       // 等同于.add(sw.output(2).to(target))
.add(node.onError(handler))      // 等同于.add(node.output(1).to(handler))
这些处理器可以和
.output(n)
调用组合使用,不会产生冲突。
ts
.add(ifNode.onTrue(targetA))
.add(ifNode.output(0).to(targetB))
// 结果:IF节点的主输出[0]同时连接到targetA和targetB。复合处理器 + .output(n)会合并连接。
唯一需要避免的写法就是上面提到的
.add(selector).to(target)
陷阱。无论之前是否使用过复合处理器,这种写法都是错误的。

After every create or update: verify

创建或更新后的必做步骤:验证

validate_workflow
reports valid even when wires are missing. After
create_workflow_from_code
or
update_workflow
, pull with
get_workflow_details
and check the
connections
object:
  • Each
    main[i]
    has the expected set of targets (fan-outs preserved, not collapsed).
  • Merge inputs land on the right indices, and
    useDataOfInput
    matches the wiring.
  • Error-output nodes have
    onError: 'continueErrorOutput'
    AND
    main[1]
    wired to a handler.
If any check fails, the workflow is broken despite passing validation. Fix and re-update.
See
references/VERIFICATION.md
for the full post-create checklist.
即使连接缺失,
validate_workflow
仍会返回验证通过。在调用
create_workflow_from_code
update_workflow
后,使用
get_workflow_details
拉取工作流并检查
connections
对象:
  • 每个
    main[i]
    包含预期的目标集合(扇出连接被保留,未被合并)。
  • Merge节点的输入连接到正确的索引,且
    useDataOfInput
    配置与连接匹配。
  • 带有错误输出的节点已设置
    onError: 'continueErrorOutput'
    ,且
    main[1]
    已连接到处理节点。
如果任何检查未通过,即使工作流通过了验证,实际也是损坏的。需要修复后重新更新。
完整的创建后检查清单请参见
references/VERIFICATION.md

Reference files

参考文档

Read the file that matches the situation. Don't read all of them:
FileRead when
references/FAN_OUT_FAN_IN.md
One source → many targets, or many sources → one target
references/MERGE_INDEX_RULES.md
Wiring a Merge node, or you see
useDataOfInput
in node config
references/ERROR_OUTPUTS.md
Adding error handling on an individual node (not error workflow, that's
n8n-error-handling
)
references/VERIFICATION.md
Just created or updated a workflow with non-trivial connections
根据场景阅读对应的文档,无需全部阅读:
文件阅读场景
references/FAN_OUT_FAN_IN.md
一个源节点 → 多个目标节点,或多个源节点 → 一个目标节点
references/MERGE_INDEX_RULES.md
配置Merge节点,或在节点配置中看到
useDataOfInput
references/ERROR_OUTPUTS.md
为单个节点添加错误处理(不是错误工作流,错误工作流请参考
n8n-error-handling
references/VERIFICATION.md
刚创建或更新了包含复杂连接的工作流

Anti-patterns

反模式

Anti-patternWhat goes wrongFix
.add(node.output(0)).to(target)
Wire silently dropped, validation passesMove
.to()
inside
.add()
Mixing
useDataOfInput: "2"
with
.input(2)
Off-by-one, wire feeds the wrong inputUse
.input(N - 1)
when
useDataOfInput: "N"
. See
MERGE_INDEX_RULES.md
Error branch wired without
onError: 'continueErrorOutput'
Branch is unreachable, and node fails the whole workflow on errorSet
onError: 'continueErrorOutput'
on the node config
Skipping
get_workflow_details
after create
Silently broken workflows shipAlways pull and inspect after create/update
Reading all four reference files before wiring one connectionWasted contextRead only the file matching the situation
反模式问题修复方案
.add(node.output(0)).to(target)
连接被静默丢弃,但验证通过
.to()
移到
.add()
内部
useDataOfInput: "2"
.input(2)
混用
索引偏移,连接传入错误的输入
useDataOfInput: "N"
时,使用
.input(N - 1)
。参见
MERGE_INDEX_RULES.md
错误分支已连接,但未设置
onError: 'continueErrorOutput'
分支无法访问,节点出错会导致整个工作流失败在节点配置中设置
onError: 'continueErrorOutput'
创建后跳过
get_workflow_details
检查
损坏的工作流被静默发布创建/更新后务必拉取并检查工作流
配置单个连接前阅读全部四份参考文档浪费时间和精力只阅读与当前场景匹配的文档