Preflight · Guides

Sub-workflows

When an n8n sub-workflow change breaks the workflows that call it

An n8n sub-workflow is shared code: when you publish a change to it, every workflow that calls it can change behavior, yet none of those parent workflows shows an edit. To ship a sub-workflow change safely, find every caller first, then run each one against your unpublished draft before you publish it.

Why doesn’t the parent workflow show a sub-workflow change?

Because the parent stores only a reference. The Execute Sub-workflow node names the sub-workflow by its workflow ID, so when the sub-workflow changes, the parent’s definition stays byte-for-byte the same. The change is visible in the sub-workflow’s own history; it is invisible from the parent, and nothing in n8n connects the two.

n8n’s documentation on workflow reviews says so directly: a review covers one workflow’s own nodes and connections, and each sub-workflow it calls is its own workflow, with its own review if any. AI agents add a second kind of caller: the Call n8n Workflow Tool node runs a sub-workflow too, and it is easy to forget when you list who depends on one.

When does a sub-workflow change reach the workflows that call it?

When you publish the sub-workflow. On n8n 2.x a parent’s production executions call the sub-workflow’s published version, so an edited but unpublished draft changes nothing for clients yet, and publishing it changes every caller at once. A manual run of the parent from the editor calls the sub-workflow’s latest draft instead, which is what makes testing before you publish possible.

We checked this on a test instance of n8n 2.44.6, because n8n’s documentation does not spell it out. The same test showed two more things worth knowing. Unpublishing a sub-workflow makes its parents’ production runs fail. And updating a published sub-workflow through n8n’s public API publishes it immediately, so a script or CI job that pushes a sub-workflow is a deploy to every caller.

Which sub-workflow changes break the parent?

Any change to what the sub-workflow returns or expects. The parent receives the output of the sub-workflow’s last node, so renaming a field, changing how many items come back, or ending on a different node changes the parent’s data, often with no error, because an expression that reads a missing field resolves to nothing.

  • Output shape. A renamed or removed field leaves {{ $json.total }} in the parent empty, not failing.
  • Item count. Returning one summary item instead of one per input, or no items at all, changes how often everything downstream runs. Zero items quietly stops the branch.
  • Inputs. When the sub-workflow’s trigger defines its inputs field by field, adding or renaming one changes what every caller has to send.
  • Errors. n8n’s documentation notes that a parent cannot trigger a sub-workflow that contains errors.
  • Not waiting. With Wait for Sub-Workflow Completion turned off, the parent carries on without the result, so a failure in the sub-workflow never appears in the parent’s execution.

Upgrades belong on this list too. In n8n 2.0, a parent that waits on a sub-workflow which pauses (a Wait node over 65 seconds, a webhook, a form, a human approval) began receiving the sub-workflow’s real output; in 1.x it received the sub-workflow’s input back. A parent built around the old behavior changed without anyone editing it.

How do I find every workflow that calls a sub-workflow?

Search every workflow definition for the sub-workflow’s ID. Export all workflows with n8n export:workflow --all and search the output for the ID, which appears in Execute Sub-workflow nodes and in the Call n8n Workflow Tool nodes AI agents use. Then limit which workflows may call it, in the sub-workflow’s settings under “This workflow can be called by”, so the list cannot quietly grow.

n8n export:workflow --all --separate --output=workflows/
grep -l "YOUR_SUB_WORKFLOW_ID" workflows/*.json

That lists one file per workflow that mentions the ID; ignore the sub-workflow’s own file, which names itself. A text search has two blind spots worth knowing. A caller that sets the ID with an expression will not match the literal ID, and a caller that embeds the sub-workflow as JSON in the node is not calling the shared workflow at all, so your change will not reach it.

How do I test a sub-workflow change before publishing it?

First test the sub-workflow on its own, then test its callers where nothing they run can reach a client. A manual run of a parent calls your unpublished draft, which is what makes it a real test, but it also runs every node in that draft for real, including ones that send, charge or update, and pins inside the sub-workflow do not stop them when a parent calls it.

  1. The sub-workflow alone. Open one of its own recent executions, use Copy to editor so it runs on an input a caller really sent, pin its nodes that reach the outside world, and compare its output with that execution’s. Pins do apply when you run the sub-workflow directly.
  2. Its callers, safely. Run each important parent manually against the draft only where the draft cannot do harm: on a development instance with test credentials, or when the sub-workflow sends nothing outside n8n. Copy to editor on a recent execution of the parent gives it a real input; compare node by node.
  3. Do not disable nodes in the draft to make the test safe. The draft is what you are about to publish, and a disabled node would ship disabled.
  4. Publish, then watch the next production run of each caller.

What does Preflight catch here, and what doesn’t it?

Not this change, yet. When Preflight replays a parent it answers every sub-workflow call from the recording, or switches the call off when there is none, and calls made through an AI agent’s workflow tool are always switched off, so a green replay of a parent says nothing about a change to the sub-workflow it calls. The replay report names each of those nodes as not vouched for rather than counting it as a pass.

Until Preflight can follow a call into the sub-workflow, the manual parent run above is the test to use.

The wider method: how to test n8n workflow changes before production. Why a clean definition diff is not enough: definition diffs vs behavior testing.

Early access

Test the change, and know what the test covered.

Preflight records real n8n executions, replays your edit in a sandbox, diffs every node’s output, and says plainly which nodes a replay could not vouch for.

One email when the beta opens. That’s the whole list.