n8n-subworkflows
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
Chinesen8n Sub-workflows
n8n子工作流
A sub-workflow is a reusable function. An Execute Workflow Trigger declares typed inputs, the body does the work, and the last node returns the output. A caller invokes it through an Execute Workflow node like any other step.
That framing buys you the things functions buy you everywhere: encapsulation, reuse, testability, replaceability. It's the primary reuse mechanism in n8n, and it's badly underused. Without it, the same logic gets copy-pasted across workflows — then a bug gets fixed in two places, the third copy gets missed, and your "identical" copies quietly drift apart.
This skill is about when to reach for a sub-workflow, how to define its input/output contract so callers (and agents) can actually use it, how to call it correctly ( vs , blocking vs fire-and-forget), and how to name it so it gets found instead of rebuilt.
alleach子工作流是一种可复用的功能。Execute Workflow Trigger声明类型化输入,主体部分执行具体操作,最后一个节点返回输出结果。调用方通过Execute Workflow节点调用它,就像调用其他步骤一样。
这种设计能带来函数式编程的优势:封装性、复用性、可测试性、可替换性。它是n8n中主要的复用机制,但目前未被充分利用。如果不使用子工作流,相同的逻辑会在多个工作流中被复制粘贴——之后修复了两处的bug,但第三处副本被遗漏,导致这些“完全相同”的副本悄然出现差异。
本技能介绍何时使用子工作流、如何定义其输入/输出契约以便调用方(包括Agent)能够实际使用、如何正确调用它(与模式、阻塞式与即发即弃式),以及如何命名它以便被找到而非重复构建。
alleachThe two non-negotiables
两项不可协商的规则
Everything else is judgement. These two are not.
其他事项可灵活判断,但这两项必须遵守。
1. Search before you build
1. 先搜索再构建
Before you write logic for a generic problem, check whether a sub-workflow already does it. The community MCP can't filter workflows by tag, so the name is the discovery surface:
n8n_list_workflows() # scan the library
n8n_get_workflow({ id: "<candidate>" }) # read its inputs/outputs + bodyIf something fits, use it and tell the user ("I found — using that"). If nothing fits, build it with a discoverable name so the next search finds it. The discovery convention (verb-first prefixes) lives in NAMING_AND_DISCOVERY.md.
Subworkflow: Parse RFC2822 date在为通用问题编写逻辑之前,先检查是否已有子工作流实现了该功能。社区MCP无法按标签筛选工作流,因此名称是发现的关键:
n8n_list_workflows() # 扫描库中内容
n8n_get_workflow({ id: "<candidate>" }) # 查看其输入/输出及主体逻辑如果有合适的子工作流,就使用它并告知用户(“我找到了——将使用该子工作流”)。如果没有合适的,就构建一个具有可发现名称的子工作流,以便后续搜索能找到它。动词优先前缀的命名规范详见NAMING_AND_DISCOVERY.md。
Subworkflow: Parse RFC2822 date2. The Execute Workflow Trigger uses "Define Below" with typed fields — not passthrough
2. Execute Workflow Trigger使用“Define Below”模式并配置类型化字段——而非直通模式
The trigger has two input modes. Default to "Define Below" with explicit typed fields. Define Below is the only mode that gives callers a schema to fill — it's what lets an AI agent pass values via and what lets structured callers map fields cleanly. Passthrough has no schema, so the trigger can't be wired as a clean agent tool and structured callers have nothing to bind to.
$fromAITwo exceptions, and only two:
- Binary input. Typed fields are JSON-only. If the sub-workflow must receive an image/file/PDF, you need passthrough so the slot flows through.
binary - Zero inputs. Define Below requires at least one field. A genuinely no-arg operation ("list active credentials", "current count") has nowhere to put an empty schema, so passthrough is the only option.
Outside those two cases, passthrough is a bug. See "Inputs and outputs as a contract" below.
触发器有两种输入模式。默认使用“Define Below”模式并配置明确的类型化字段。Define Below是唯一能为调用方提供填充 schema 的模式——它支持AI Agent通过传递值,也便于结构化调用方清晰映射字段。直通模式没有schema,因此触发器无法作为简洁的Agent工具进行连接,结构化调用方也没有可绑定的对象。
$fromAI仅有两种例外情况:
- 二进制输入:类型化字段仅支持JSON格式。如果子工作流必须接收图片/文件/PDF,则需要使用直通模式,以便槽能正常流转。
binary - 零输入:Define Below模式要求至少有一个字段。真正无参数的操作(如“列出活跃凭据”、“当前计数”)无法设置空schema,因此只能使用直通模式。
除这两种情况外,使用直通模式均视为错误。详见下文“作为契约的输入与输出”。
Should this be a sub-workflow?
是否应该将逻辑提取为子工作流?
You're about to write a chunk of logic. Run it through this:
Could this plausibly be needed in another workflow?
└─ Yes → extract.
Is it a generic concern (auth, retry, parsing, formatting, ID generation)?
└─ Almost always → extract. These are the canonical reusable sub-workflows.
Is it >5 nodes and conceptually one thing?
└─ Probably extract, even if reuse isn't certain. It's better isolated.
Is it one HTTP call with no logic around it?
└─ Don't. A sub-workflow that's just trigger → HTTP → return adds a boundary
for nothing.
Is it tightly coupled to this one caller's data shape?
└─ Don't extract yet — fix the data shape first, or you just relocate the coupling.The reasons to extract go beyond reuse:
- Readability. The caller shows one node ("Parse date") instead of five.
- Testability. Run the sub-workflow alone with pinned input ().
n8n_test_workflow - Replaceability. Swap the implementation without rippling to callers.
A 20-node workflow is fine if it's mostly a linear sequence of Execute Workflow calls and decisions — each node has one purpose, and you inspect a section by opening the sub-workflow it calls. A 20-node workflow of inline transformations is not fine. If yours has 15+ nodes and isn't mostly sub-workflow calls and branches, extract more.
当你准备编写一段逻辑时,可通过以下问题判断:
这段逻辑是否可能在其他工作流中被需要?
└─ 是 → 提取为子工作流。
它是否属于通用关注点(认证、重试、解析、格式化、ID生成)?
└─ 几乎总是 → 提取为子工作流。这些是典型的可复用子工作流场景。
它是否包含>5个节点且在概念上属于单一功能?
└─ 可能需要提取,即使不确定是否会复用。这样能更好地实现隔离。
它是否只是一个无额外逻辑的HTTP调用?
└─ 无需提取。仅包含触发器→HTTP→返回的子工作流只会增加不必要的边界。
它是否与当前调用方的数据形态紧密耦合?
└─ 暂不提取——先修复数据形态,否则只是将耦合转移到子工作流中。提取为子工作流的理由不止于复用:
- 可读性:调用方只需显示一个节点(如“解析日期”),而非五个节点。
- 可测试性:可单独运行子工作流并使用固定输入()。
n8n_test_workflow - 可替换性:无需修改调用方即可替换实现逻辑。
如果一个20节点的工作流主要由Execute Workflow调用和决策步骤组成,则是可行的——每个节点都有单一用途,你可以通过打开它调用的子工作流来查看对应部分的逻辑。但一个包含大量内联转换的20节点工作流则不可取。如果你的工作流有15个以上节点且并非主要由子工作流调用和分支组成,那么需要更多地提取子工作流。
Stateless vs. stateful (deliberately)
无状态与有状态(刻意设计)
Both are first-class. The choice is about intent and what the contract promises.
Stateless — input in, output out, no I/O beyond that. The default for pure logic. When you need it again, you call it without worrying about side effects firing.
- — date string → ISO date or error.
Subworkflow: Parse RFC2822 date - — subscription object → number.
Subworkflow: Compute MRR from subscription - — invoice data → HTML string.
Subworkflow: Format invoice as HTML
Stateful (deliberate) — reads or writes external state behind a clean contract. This is the repository pattern: the sub-workflow abstracts the storage operation so callers think in domain terms, not SQL.
- — id → customer object or
Customer: get by id. Reads the DB.{ ok: false, error: "not_found" } - — record →
Customer: write billing record. Writes the DB.{ ok: true, id } - — channel, message →
Notify: send to on-call. Calls Slack/SMTP.{ ok: true, messageId }
Why build these as sub-workflows: callers think instead of writing the query; you can swap the store (Postgres → Supabase, native node → HTTP) without touching a single caller; and idempotency, retry, and validation get centralized in one place.
get customer by idWhat to avoid is accidental state — a sub-workflow named and described as pure that quietly writes to a log table. That ambushes every caller who reasonably assumed it was safe to retry or compose. Either make the side effect part of the contract (rename it, document it, return its result) or move it out.
两者都是一等公民。选择取决于设计意图及契约承诺的内容。
无状态——输入进,输出出,除此之外无其他I/O操作。适用于纯逻辑场景。当你再次需要它时,调用它无需担心触发副作用。
- ——日期字符串→ISO日期或错误信息。
Subworkflow: Parse RFC2822 date - ——订阅对象→数值。
Subworkflow: Compute MRR from subscription - ——发票数据→HTML字符串。
Subworkflow: Format invoice as HTML
有状态(刻意设计)——通过清晰的契约读取或写入外部状态。这是仓储模式的应用:子工作流抽象存储操作,使调用方从领域术语的角度思考,而非SQL语句。
- ——ID→客户对象或
Customer: get by id。读取数据库。{ ok: false, error: "not_found" } - ——记录→
Customer: write billing record。写入数据库。{ ok: true, id } - ——渠道、消息→
Notify: send to on-call。调用Slack/SMTP。{ ok: true, messageId }
为何将这些实现为子工作流:调用方只需思考“通过ID获取客户”,而非编写查询语句;你可以替换存储系统(从Postgres到Supabase,从原生节点到HTTP)而无需修改任何调用方;幂等性、重试和验证逻辑可集中在一处处理。
需要避免的是意外状态——一个名称和描述都表明是纯逻辑的子工作流,却悄悄写入日志表。这会让每个合理假设它可安全重试或组合的调用方陷入困境。要么将副作用纳入契约(重命名、文档说明、返回结果),要么将其移出子工作流。
Inputs and outputs as a contract
作为契约的输入与输出
The trigger's declared fields and the last node's output shape are the sub-workflow's API. Treat them like one.
触发器声明的字段和最后一个节点的输出形态就是子工作流的API。需将它们视为一个整体。
Declaring typed inputs (Define Below)
声明类型化输入(Define Below模式)
Each declared input is a typed parameter the caller fills. Pick types deliberately (, , , , ) — an agent uses these as the required types when filling tool parameters, and humans rely on them when wiring callers. The trigger node parameters look like this:
stringnumberbooleanarrayobjectjson
{
"type": "n8n-nodes-base.executeWorkflowTrigger",
"parameters": {
"workflowInputs": {
"values": [
{ "name": "list_of_ids", "type": "array" },
{ "name": "include_transcript", "type": "boolean" },
{ "name": "session_id", "type": "string" }
]
}
}
}Inside the body, read them as , or from anywhere downstream as (see n8n-expression-syntax).
$json.list_of_ids$('When Executed by Another Workflow').first().json.<field>每个声明的输入都是调用方需要填充的类型化参数。需谨慎选择类型(、、、、)——Agent在填充工具参数时会使用这些必填类型,人类在连接调用方时也依赖这些类型信息。触发器节点参数示例如下:
stringnumberbooleanarrayobjectjson
{
"type": "n8n-nodes-base.executeWorkflowTrigger",
"parameters": {
"workflowInputs": {
"values": [
{ "name": "list_of_ids", "type": "array" },
{ "name": "include_transcript", "type": "boolean" },
{ "name": "session_id", "type": "string" }
]
}
}
}在主体逻辑中,可通过读取输入,或在下游任意位置通过读取(详见n8n-expression-syntax)。
$json.list_of_ids$('When Executed by Another Workflow').first().json.<field>The contract rules
契约规则
- Document inputs and outputs in the workflow . Field names, types, purpose, and a few representative keywords. The description is what callers (human and agent) read for the contract, and it's what
descriptionmatches against.n8n_list_workflows - Return consistent, natural shapes — not storage shapes. A sub-workflow that owns a Data Table or an S3 file hides that representation from callers. Arrays return as arrays, objects as objects, dates as ISO strings — regardless of whether the underlying storage was JSON-stringified text. The return contract is the interface; the storage layout is implementation detail. Common slip: a sub-workflow with a "fresh" path (just-computed, natural shape) and a "cached" path (just read from a stringified column). Wrong instinct: stringify the fresh path to match the cached one. Right instinct: parse the cached path so both return the natural shape.
- Return errors, don't always throw. For expected failures (a parse error, a not-found), return so the caller can branch without wiring an error output. Reserve throwing for genuinely unexpected failures — see n8n-error-handling.
{ ok: false, error: "..." } - The contract is frozen once it has callers. Adding optional fields is safe. Renaming or removing a field is dangerous: n8n won't error on an unrecognized input field — the body just sees , the caller has no idea, and you get a silent contract break. To change a field, enumerate every caller (
undefined+ inspect each one's Execute Workflow node), migrate them in the same change, and verify withn8n_list_workflowsandvalidate_workflowbefore you're done.n8n_get_workflow
- 在工作流中记录输入与输出:包括字段名称、类型、用途及一些代表性关键词。描述是调用方(人类和Agent)了解契约的依据,也是
description进行匹配的对象。n8n_list_workflows - 返回一致、自然的数据形态——而非存储形态:拥有数据表或S3文件的子工作流应向调用方隐藏其存储表示。数组返回为数组,对象返回为对象,日期返回为ISO字符串——无论底层存储是否为JSON字符串化的文本。返回契约是接口;存储布局是实现细节。常见错误:子工作流有“新鲜”路径(刚计算出的自然形态)和“缓存”路径(刚从字符串化列读取的形态)。错误做法:将新鲜路径字符串化以匹配缓存路径。正确做法:解析缓存路径,使两者都返回自然形态。
- 返回错误信息,而非总是抛出异常:对于预期内的失败(如解析错误、未找到资源),返回,以便调用方可进行分支处理而无需连接错误输出。仅对真正意外的失败保留抛出异常的方式——详见n8n-error-handling。
{ ok: false, error: "..." } - 一旦有调用方使用,契约即冻结:添加可选字段是安全的。重命名或删除字段则很危险:n8n不会对未识别的输入字段报错——主体逻辑只会看到,调用方毫无察觉,从而导致契约静默失效。如需修改字段,需枚举所有调用方(
undefined+ 检查每个调用方的Execute Workflow节点),在同一变更中迁移它们,并在完成前使用n8n_list_workflows和validate_workflow进行验证。n8n_get_workflow
The final Return node — the legitimate Set exception
最终的Return节点——合理的Set节点例外情况
Shape the output with a final Set / Edit Fields node, named or . This is the one place a Set node earns its keep against the usual "don't add a trailing Set node" advice from n8n-expression-syntax: the implicit consumer of a sub-workflow's last node is every caller, so an explicit Set makes the return contract visible — a reader sees the whole API by reading one node, and you strip any noise fields the last computation node carried.
ReturnReturn <thing>使用最终的Set / Edit Fields节点(命名为或)来塑造输出形态。这是唯一一处Set节点值得使用的场景,与n8n-expression-syntax中“不要添加末尾Set节点”的常规建议相悖:子工作流最后一个节点的隐式消费者是所有调用方,因此显式的Set节点能使返回契约可见——读者只需查看一个节点就能了解整个API,同时还能清除最后计算节点携带的无用字段。
ReturnReturn <thing>Calling sub-workflows: mode
and waitForSubWorkflow
modewaitForSubWorkflow调用子工作流:mode
与waitForSubWorkflow
modewaitForSubWorkflowTwo settings on the caller's Execute Workflow node decide how the sub-workflow runs.
调用方的Execute Workflow节点有两个设置决定子工作流的运行方式。
mode
: all
vs each
modealleachmode
:all
与each
modealleach | Sub-workflow runs | Items per run |
|---|---|---|
| once | all N items (flowing per-item through nodes as usual) |
| N times | exactly one item per run |
For a body that just processes items the normal way, the two are equivalent — n8n nodes iterate per-item either way. The split only matters when the body assumes it sees exactly one item: a per-run aggregation, "this is THE customer to act on" logic, or a final write that should fire once per input. With , that body gets all N items at once and the assumption breaks (you aggregate everyone into one result instead of one-per-input). With , each invocation gets one item and the assumption holds.
alleachSo: when you need per-item iteration, prefer over dropping a Loop Over Items node inside the sub-workflow. The mode does the iteration for you, and the body stays simple and single-item.
mode: each | 子工作流运行次数 | 每次运行处理的条目数 |
|---|---|---|
| 1次 | 所有N个条目(按常规在节点间逐条目流转) |
| N次 | 每次运行恰好处理1个条目 |
对于仅按常规方式处理条目的主体逻辑,两种模式效果相同——n8n节点无论哪种模式都会逐条目迭代。差异仅在主体逻辑假设每次只处理一个条目时才会显现:如每次运行的聚合操作、“这是要处理的唯一客户”逻辑,或每次输入应触发一次的最终写入操作。使用模式时,主体逻辑会一次性获取所有N个条目,从而打破假设(将所有输入聚合为一个结果,而非每个输入对应一个结果)。使用模式时,每次调用都会获取一个条目,假设得以成立。
alleach因此:当需要逐条目迭代时,优先选择,而非在子工作流内部添加Loop Over Items节点。该模式会替你完成迭代,使主体逻辑保持简洁且仅处理单个条目。
mode: eachwaitForSubWorkflow
: true
vs false
waitForSubWorkflowtruefalsewaitForSubWorkflow
:true
与false
waitForSubWorkflowtruefalsewaitForSubWorkflowtrueoptions.waitForSubWorkflow: falsewaitForSubWorkflowtrueoptions.waitForSubWorkflow: falseThe only true parallelization n8n offers
n8n提供的唯一真正并行化方式
mode: eachwaitForSubWorkflow: falsemode: eachwaitForSubWorkflow: falseSplitting by input shape (the N+1 pattern)
按输入形态拆分(N+1模式)
When a sub-workflow has multiple input paths whose contracts genuinely differ — binary vs JSON, sync vs async, divergent auth schemes — don't cram them under one trigger with passthrough + an internal Switch. The forcing function is real: passthrough (for binary or zero-input) and Define Below (for typed inputs) are mutually exclusive on a single trigger. The reflex to "pick passthrough because it's most permissive, then branch inside" costs you the typed schema (no clean agent tool), grows branch-shape cruft, and turns every new input shape into more branching.
The fix: for N divergent input contracts, build N+1 sub-workflows — one outer per contract, each doing its input-specific prep (validation, fetching, hashing, extraction) and calling one shared downstream sub-workflow with a normalized shape. The shared core has a single typed input contract and knows nothing about which outer called it. The worked example (process a paper from an external ID or an uploaded PDF) is in SUBWORKFLOW_PATTERNS.md.
当子工作流有多个输入路径且其契约确实存在差异时(如二进制与JSON、同步与异步、不同的认证方案),不要将它们塞进一个使用直通模式+内部Switch节点的触发器中。现实限制是:直通模式(用于二进制或零输入)与Define Below模式(用于类型化输入)在单个触发器上互斥。“选择直通模式因为它最灵活,然后在内部分支”的本能做法会让你失去类型化schema(无法作为简洁的Agent工具),增加分支形态的冗余,并使每个新输入形态都需要更多分支。
解决方案:对于N种不同的输入契约,构建N+1个子工作流——每个外部子工作流对应一种契约,完成输入特定的预处理(验证、获取、哈希、提取),并调用一个共享的下游子工作流,该子工作流使用标准化形态。共享核心子工作流只有一个类型化输入契约,且无需了解是哪个外部子工作流调用了它。具体示例(从外部ID或上传的PDF处理文档)详见SUBWORKFLOW_PATTERNS.md。
Sub-workflow as an agent tool
作为Agent工具的子工作流
A sub-workflow with a typed Define Below trigger doubles as an AI-agent tool: the agent fills the declared fields via , the body runs, the result comes back as the tool observation. This is the high-value reason to default to Define Below — passthrough triggers can't expose a fill-able schema.
$fromAIThe zero-input case still works as a tool: the agent's only decision is whether to invoke. The binary case does not wire cleanly as a tool, because agents can't pass binary directly.
For tool naming, descriptions, and the binary-input workaround, see n8n-agents; for the binary handling itself, n8n-binary-and-data.
使用类型化Define Below触发器的子工作流可直接作为AI Agent工具:Agent通过填充声明的字段,主体逻辑运行,结果作为工具观察结果返回。这是默认使用Define Below模式的高价值原因——直通模式触发器无法暴露可填充的schema。
$fromAI零输入场景仍可作为工具:Agent只需决定是否调用即可。二进制场景则无法作为工具正常连接,因为Agent无法直接传递二进制数据。
关于工具命名、描述及二进制输入的解决方法,详见n8n-agents;二进制数据处理本身详见n8n-binary-and-data。
Anti-patterns
反模式
| Anti-pattern | What goes wrong | Fix |
|---|---|---|
| Duplicating the same logic in three workflows | A bug gets fixed in two places, the third drifts | Extract once to a named sub-workflow |
| Building a new sub-workflow without searching | The library grows duplicates; future searches find both | |
| Trigger set to passthrough when not handling binary and not zero-input | No schema → agents can't fill params, structured callers can't bind | Use Define Below with typed |
| Zero-input passthrough with no clear-and-document | Body silently reads stray fields from whatever the caller forwarded | Start with a Set ("Keep Only Set", no fields) and a sticky noting "no inputs expected" |
| Sub-workflow named/described as pure that quietly writes state | Callers can't reason about retry/idempotency; the side effect ambushes them | Make the side effect part of the contract, or move it out |
Sub-workflow with no | Won't be found in future searches; nobody knows what it does | Set |
Name like | Doesn't say what it does, matches no prefix search | Verb-first prefix ( |
| Aggregates all inputs into one result instead of one-per-input | |
| Renaming a live input field without migrating callers | Callers send the old name → body sees | Migrate every caller in the same change; verify with |
| 30-node workflow with no extraction | Hard to read, test, and replace | Extract logical sections into sub-workflows |
| 反模式 | 问题所在 | 修复方案 |
|---|---|---|
| 在三个工作流中重复相同的逻辑 | 修复了两处bug,但第三处副本出现差异 | 将逻辑提取为一个命名子工作流 |
| 未搜索就构建新的子工作流 | 库中出现重复内容;后续搜索会找到多个结果 | 先使用 |
| 非二进制输入且非零输入场景下使用直通模式触发器 | 无schema→Agent无法填充参数,结构化调用方无法绑定 | 使用Define Below模式并配置类型化 |
| 使用零输入直通模式但未明确记录 | 主体逻辑会悄悄读取调用方传递的任意杂散字段 | 以一个“仅保留设置”的Set节点(无字段)开头,并添加便签说明“无输入预期” |
| 名称/描述为纯逻辑但悄悄写入状态的子工作流 | 调用方无法判断是否可重试/幂等;副作用会意外触发 | 将副作用纳入契约,或移出子工作流 |
无 | 后续搜索无法找到;无人知晓其用途 | 设置 |
名称类似 | 未说明功能,无法匹配前缀搜索 | 使用动词优先前缀( |
主体逻辑假设单个条目却使用 | 将所有输入聚合为一个结果,而非每个输入对应一个结果 | 使用 |
| 未迁移调用方就重命名已在使用的输入字段 | 调用方发送旧字段名→主体逻辑看到 | 在同一变更中迁移所有调用方;使用 |
| 30节点工作流未提取子工作流 | 难以阅读、测试和替换 | 将逻辑部分提取为子工作流 |
What's NOT available via the community MCP
社区MCP无法实现的功能
| Want to do | Reality |
|---|---|
| Filter/discover workflows by tag | The MCP can't read or filter by tags (UI-only). Discovery is the name — use verb-first prefixes and |
| Catch an unrecognized input field | n8n doesn't error on one. The body sees |
| Set the input mode / fields without a typed trigger | The trigger node itself must declare |
What the MCP can do: build the sub-workflow and its callers ( with / / / ), discover existing ones (, ), validate (, ), test in isolation (), inspect runs (), back a stateful sub-workflow with a Data Table (), and activate ().
n8n_update_partial_workflowaddNodeaddConnectionupdateNodepatchNodeFieldn8n_list_workflowsn8n_get_workflowvalidate_workflown8n_validate_workflown8n_test_workflown8n_executionsn8n_manage_datatableactivateWorkflow| 想要实现的操作 | 实际情况 |
|---|---|---|
| 按标签筛选/发现工作流 | MCP无法读取或按标签筛选(仅UI支持)。发现依赖于名称——使用动词优先前缀和。 |
| 捕获未识别的输入字段 | n8n不会对此报错。主体逻辑会看到,调用方毫无察觉——导致契约静默失效。手动验证调用方的字段变更。 |
| 无需类型化触发器即可设置输入模式/字段 | 触发器节点本身必须声明。使用( / )进行配置;使用 / 验证。 |
n8n_list_workflowsundefinedworkflowInputs.valuesn8n_update_partial_workflowupdateNodepatchNodeFieldget_nodevalidate_nodeMCP可以实现的功能:构建子工作流及其调用方(使用的 / / / )、发现现有子工作流(、)、验证(、)、单独测试()、检查运行情况()、使用数据表支持有状态子工作流()、激活工作流()。
n8n_update_partial_workflowaddNodeaddConnectionupdateNodepatchNodeFieldn8n_list_workflowsn8n_get_workflowvalidate_workflown8n_validate_workflown8n_test_workflown8n_executionsn8n_manage_datatableactivateWorkflowReference files
参考文件
| File | Read when |
|---|---|
| SUBWORKFLOW_PATTERNS.md | |
| NAMING_AND_DISCOVERY.md | Naming a new sub-workflow, the verb-first prefix convention, searching for existing ones, writing a discoverable description |
| 文件 | 阅读场景 |
|---|---|
| SUBWORKFLOW_PATTERNS.md | 深入了解 |
| NAMING_AND_DISCOVERY.md | 为新子工作流命名、动词优先前缀规范、搜索现有子工作流、编写便于发现的描述 |
Integration with other skills
与其他技能的集成
- n8n-workflow-patterns — use it for the overall shape of the orchestrating workflow; use this skill to decide which sections become sub-workflows.
- n8n-mcp-tools-expert — parameter formats for ,
n8n_list_workflows,n8n_get_workflow, andn8n_update_partial_workflow(the Data Table behind a stateful sub-workflow and the fire-and-forget poll).n8n_manage_datatable - n8n-node-configuration — and the
workflowInputs(Define Below vs passthrough) toggle are displayOptions-driven config on the Execute Workflow Trigger.inputSource - n8n-expression-syntax — reading inputs (,
$json) and the legitimate final-Set exception both live here.$('When Executed by Another Workflow') - n8n-error-handling — expected failures return ; unexpected ones throw and route through error outputs. A sub-workflow boundary is a natural place to define that line.
{ ok: false, error } - n8n-validation-expert — validate the sub-workflow and its callers; an unrecognized input field won't surface here, so verify field changes manually.
- n8n-code-javascript / n8n-code-python — when a sub-workflow's body is a single Code node, its contract is still the trigger's typed inputs and the returned shape, not the Code node's internals.
- n8n-code-tool — the Custom Code Tool is the inline agent-tool option; a sub-workflow tool is the reusable, multi-step one. Pick the sub-workflow when the logic is shared across agents or needs the full Code-node sandbox.
- n8n-agents — wiring a typed sub-workflow as an agent tool, including the zero-input and binary cases.
- n8n-binary-and-data — passthrough triggers for binary input, and why binary can't flow through an agent tool directly.
- using-n8n-mcp-skills — when to consult which skill across a build.
- n8n-workflow-patterns——用于编排工作流的整体形态;使用本技能判断哪些部分应提取为子工作流。
- n8n-mcp-tools-expert——、
n8n_list_workflows、n8n_get_workflow和n8n_update_partial_workflow(有状态子工作流和即发即弃轮询背后的数据表)的参数格式。n8n_manage_datatable - n8n-node-configuration——和
workflowInputs(Define Below与直通模式)切换是Execute Workflow Trigger基于displayOptions的配置。inputSource - n8n-expression-syntax——读取输入(、
$json)和合理的末尾Set节点例外情况均在此处说明。$('When Executed by Another Workflow') - n8n-error-handling——预期内失败返回;意外失败抛出异常并通过错误输出路由。子工作流边界是定义该界限的天然位置。
{ ok: false, error } - n8n-validation-expert——验证子工作流及其调用方;未识别的输入字段不会在此处暴露,因此需手动验证字段变更。
- n8n-code-javascript / n8n-code-python——当子工作流的主体是单个Code节点时,其契约仍是触发器的类型化输入和返回形态,而非Code节点的内部逻辑。
- n8n-code-tool——自定义代码工具是内联Agent工具选项;子工作流工具是可复用的多步骤工具。当逻辑在多个Agent间共享或需要完整的Code节点沙箱时,选择子工作流。
- n8n-agents——将类型化子工作流连接为Agent工具,包括零输入和二进制场景。
- n8n-binary-and-data——用于二进制输入的直通模式触发器,以及二进制数据无法直接通过Agent工具流转的原因。
- using-n8n-mcp-skills——构建过程中何时参考哪些技能。
Quick reference checklist
快速参考检查清单
Before shipping a sub-workflow:
- Searched first with /
n8n_list_workflows— it doesn't already existn8n_get_workflow - Trigger uses Define Below with typed (unless binary or zero-input)
workflowInputs.values - Zero-input passthrough (if used) starts with a "Keep Only Set" Set node + a sticky noting no inputs
- Name has a verb-first prefix (,
Subworkflow:,<Domain>:)Tool: - Description documents input/output shape and carries searchable keywords
- Returns a natural, consistent shape via a final Set node — not a storage shape
Return - Expected failures return ; only unexpected ones throw
{ ok: false, error } - Caller is
modeif the body assumes a single item (not an internal Loop Over Items)each - is set deliberately (
waitForSubWorkflowonly with a completion-tracking mechanism)false - Stateful sub-workflows declare their side effect in name + description — no accidental state
- Validated with ; tested in isolation with
validate_workflown8n_test_workflow
Remember: a sub-workflow is a function. Its API is the trigger's typed inputs and the last node's output shape — make both explicit, name it so it's found, and call it with the its body expects. A passthrough trigger that isn't for binary or a zero-arg op, or a name nobody can search, is how a reusable function quietly becomes the next duplicate.
mode在发布子工作流前:
- 已先搜索使用/
n8n_list_workflows——确认该子工作流不存在n8n_get_workflow - 触发器使用Define Below模式并配置类型化(二进制或零输入场景除外)
workflowInputs.values - 零输入直通模式(若使用)以“仅保留设置”的Set节点开头,并添加便签说明无输入预期
- 名称带有动词优先前缀(、
Subworkflow:、<Domain>:)Tool: - 描述记录了输入/输出形态及可搜索关键词
- 通过最终的Set节点返回自然、一致的形态——而非存储形态
Return - 预期内失败返回;仅意外失败抛出异常
{ ok: false, error } - **调用方**在主体逻辑假设单个条目时设置为
mode(而非内部的Loop Over Items节点)each - ****是刻意设置的(仅在有完成跟踪机制时设置为
waitForSubWorkflow)false - 有状态子工作流在名称和描述中声明其副作用——无意外状态
- 已验证使用;已使用
validate_workflow单独测试n8n_test_workflow
记住:子工作流就是一个函数。其API是触发器的类型化输入和最后一个节点的输出形态——需使两者都明确可见,命名以便被找到,并按主体逻辑预期的调用它。非二进制或无参数场景下使用直通模式触发器,或使用无法被搜索到的名称,会让一个可复用的函数悄然成为下一个重复逻辑。
mode