Sub-Workflow(子工作流)是n8n中一个强大的功能,它允许你把一个大的、复杂的工作流分解成多个更小、可复用的工作流模块。想象一下,就像编程中的函数一样——你可以创建一个做特定事情的Sub-Workflow,然后在多个地方调用它。
| 特性 | 说明 |
|---|---|
| 模块化 | 把复杂逻辑拆分成独立的、易于维护的单元 |
| 复用性 | 同一个Sub-Workflow可以被多个主工作流调用 |
| 可读性 | 主工作流看起来更清晰,逻辑更容易理解 |
| 易于测试 | 可以独立测试每个Sub-Workflow的功能 |
| 性能优化 | 避免工作流过大导致的内存问题 |
| 执行独立性 | Sub-Workflow执行不计入活跃工作流额度限制 |
要将部分工作流转换为Sub-Workflow,首先需要选择合适的节点。选择是连续的,这意味着所有选中的节点必须形成一条完整的链路。
✅ 必须满足:
错误示例1:包含触发节点
❌ Webhook → HTTP Request → Slack → Sub-Workflow
(不能包含Webhook作为触发节点)
错误示例2:输入节点是Merge(多输入汇聚)
❌ API调用1 ─┐
├─→ Merge → Set → 子工作流 (错误:Merge不能作为Sub-Workflow输入)
API调用2 ─┘
错误示例3:输出节点是If(条件分支)
❌ 子工作流 → If节点 ─→ 分支1 (错误:If节点有多个分支输出)
└→ 分支2
正确示例:
✅ HTTP Request → Set → Function → Slack
(连续、清晰的单一链路,可安全转换为Sub-Workflow)转换Sub-Workflow的步骤非常简单:
Shift 键,点击最后一个节点(自动选中中间的所有节点)Ctrl/Cmd 键就这样! 你的工作流现在变得更加模块化了。
转换完成后,还需要手动配置数据类型约束,这对于确保数据传递的安全性和准确性非常重要。
打开新创建的Sub-Workflow,找到"Execute Sub-workflow Trigger"节点:
步骤:
| 模式 | 说明 | 适用场景 |
|---|---|---|
| Define using fields below | 手动定义每个输入字段的名称和类型 | 数据结构清晰、字段明确的场景 |
| Define using JSON example | 提供一个JSON示例,n8n自动推断类型 | 输入数据格式复杂时 |
| Accept all data | 接收任何数据,不限制类型 | 快速原型化或兼容多种数据源 |
推荐做法:
{
"customerName": "John Doe",
"email": "john@example.com",
"amount": 99.99,
"isVIP": true
}使用JSON示例,n8n会自动识别:
customerName → Stringamount → NumberisVIP → Boolean找到Sub-Workflow中的最后一个节点,添加"Return"(返回)节点来定义输出:
步骤:
示例输出配置:
字段名: result
类型: Object
字段名: status
类型: String
字段名: timestamp
类型: DateTime现在回到原始工作流,查看新生成的"Execute Sub-workflow"节点:
输入: customerName
值: {{ $node["HTTP Request"].json.name }}
输入: email
值: {{ $node["Previous Node"].json.contactEmail }}n8n的Sub-Workflow转换虽然强大,但有一些需要特别注意的地方:
使用 first()、last()、all() 这样的访问器函数时要特别小心:
// ❌ 这种写法在转换后可能不工作
{{ $node["previous"].json.items[0] }}
// ✅ 转换后会变成
{{ $node["previous"]_firstItem.json }}n8n会自动添加后缀:
_firstItem - 获取第一条数据_lastItem - 获取最后一条数据_allItems - 获取所有数据建议: 转换后务必检查表达式是否正确工作!
如果Sub-Workflow包含AI工具类节点:
v1 执行顺序// ❌ 不支持:使用表达式作为索引
itemMatching({{ $node.previousNode.json.index }})
// ✅ 支持:只能使用固定数字
itemMatching(0) // 第0项
itemMatching(1) // 第1项现在让我们看一个实际的、可执行的工作流示例。这个工作流演示了:
{
"name": "Customer Data Processing with Sub-Workflow",
"nodes": [
{
"parameters": {
"triggerEvents": [
"form_submit"
]
},
"id": "webhook-trigger-a1b2c3",
"name": "Webhook",
"type": "n8n-nodes-base.webhook",
"typeVersion": 1,
"position": [
100,
140
]
},
{
"parameters": {
"url": "https://api.example.com/customers/{{ $node.Webhook.json.customerId }}",
"method": "GET"
},
"id": "http-request-d4e5f6",
"name": "Get Customer Data",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4,
"position": [
300,
140
]
},
{
"parameters": {
"options": {}
},
"id": "execute-subworkflow-g7h8i9",
"name": "Execute Sub-Workflow",
"type": "n8n-nodes-base.executeWorkflow",
"typeVersion": 1,
"position": [
550,
140
]
},
{
"parameters": {
"method": "POST",
"url": "https://api.example.com/customers",
"sendBody": true,
"bodyParameters": {
"parameters": [
{
"name": "name",
"value": "={{ $node['Transform Data'].json.cleanName }}"
},
{
"name": "email",
"value": "={{ $node['Transform Data'].json.email }}"
},
{
"name": "status",
"value": "={{ $node['Transform Data'].json.status }}"
}
]
}
},
"id": "http-save-j0k1l2",
"name": "Save to Database",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4,
"position": [
800,
140
]
}
],
"connections": {
"webhook-trigger-a1b2c3": {
"main": [
[
{
"node": "Get Customer Data",
"type": "main",
"index": 0
}
]
]
},
"http-request-d4e5f6": {
"main": [
[
{
"node": "Execute Sub-Workflow",
"type": "main",
"index": 0
}
]
]
},
"execute-subworkflow-g7h8i9": {
"main": [
[
{
"node": "Save to Database",
"type": "main",
"index": 0
}
]
]
}
}
}这个Sub-Workflow负责清理、验证和转换客户数据:
{
"name": "Transform and Validate Customer Data",
"nodes": [
{
"parameters": {
"inputType": "defineBelow",
"inputs": {
"fields": [
{
"name": "firstName",
"type": "string",
"required": true
},
{
"name": "lastName",
"type": "string",
"required": true
},
{
"name": "email",
"type": "string",
"required": true
}
]
}
},
"id": "subwf-trigger-m3n4o5",
"name": "When Executed by Another Workflow",
"type": "n8n-nodes-base.executeWorkflowTrigger",
"typeVersion": 1,
"position": [
100,
140
]
},
{
"parameters": {
"assignments": [
{
"name": "cleanName",
"type": "expression",
"value": "{{ ($node['When Executed by Another Workflow'].json.firstName + ' ' + $node['When Executed by Another Workflow'].json.lastName).trim() }}"
},
{
"name": "email",
"type": "expression",
"value": "={{ $node['When Executed by Another Workflow'].json.email.toLowerCase().trim() }}"
},
{
"name": "status",
"type": "string",
"value": "active"
}
]
},
"id": "set-transform-p6q7r8",
"name": "Transform Data",
"type": "n8n-nodes-base.set",
"typeVersion": 3,
"position": [
350,
140
]
},
{
"parameters": {
"condition": "expression",
"value": "={{ /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test($node['Transform Data'].json.email) }}"
},
"id": "if-validate-s9t0u1",
"name": "Validate Email",
"type": "n8n-nodes-base.if",
"typeVersion": 1,
"position": [
550,
140
]
},
{
"parameters": {
"assignments": [
{
"name": "cleanName",
"type": "expression",
"value": "={{ $node['Transform Data'].json.cleanName }}"
},
{
"name": "email",
"type": "expression",
"value": "={{ $node['Transform Data'].json.email }}"
},
{
"name": "status",
"type": "string",
"value": "active"
}
]
},
"id": "set-return-v2w3x4",
"name": "Return",
"type": "n8n-nodes-base.set",
"typeVersion": 3,
"position": [
750,
140
]
}
],
"connections": {
"subwf-trigger-m3n4o5": {
"main": [
[
{
"node": "Transform Data",
"type": "main",
"index": 0
}
]
]
},
"set-transform-p6q7r8": {
"main": [
[
{
"node": "Validate Email",
"type": "main",
"index": 0
}
]
]
},
"if-validate-s9t0u1": {
"main": [
[
{
"node": "Return",
"type": "main",
"index": 0
}
]
]
}
]
}症状: 报错 Cannot read property 'xxx' of undefined
解决方案:
first()、last()、all()_firstItem、_lastItem、_allItems症状: Execute Sub-Workflow节点报红色错误
解决方案:
症状: Sub-Workflow接收到null或类型错误的数据
解决方案:
症状: AI相关功能在Sub-Workflow中失效
解决方案:
Sub-Workflow转换是n8n中实现工作流模块化的强大工具。通过本教程,你现在已经掌握了:
✅ Sub-Workflow的核心概念和优势
✅ 节点选择的5个关键规则
✅ 自动转换的完整过程
✅ 输入/输出的配置方法
✅ 常见限制和注意事项
✅ 一个完整的可执行实战案例
✅ 最佳实践和问题排查方法
现在,你已经可以开始构建更加高效、可维护的n8n工作流了。记住,好的模块化设计不仅能提高开发效率,还能让团队协作更加顺畅!
[1] 官方文档: https://docs.n8n.io/workflows/subworkflow-conversion/
[2] n8n系列教程: https://www.undsky.com/blog/?category=n8n%E6%95%99%E7%A8%8B#