Skip to main content

Sub Flow

Calls another saved flow as a function.

This is the node that turns a collection of flows into a maintainable system. Everything about building large automation depends on using it well.

Purpose

Runs a saved flow inline against the shared execution context, optionally passing arguments, then branches on the status the child returned.

When to use it

  • A sequence of steps is used by more than one flow.
  • A flow has grown past what you can read on one screen.
  • You want to test a piece of logic in isolation.
  • A routine needs to behave differently per caller, via arguments.

When not to use it

  • For two nodes used once. The indirection costs more than it saves.
  • To call itself. Recursion is rejected at run time via the live call stack.
  • When the child needs to write back many values — a child communicates through its status, not by returning a payload.

Requirements

A saved flow to call. The child should declare any values it needs as Flow Input Parameters.

How it runs

The child runs to its own Stop or Return. That node's declared status is the child's return value, and it selects which port the parent leaves through.

Self-reference and circular calls are rejected at run time by the live call stack — the schema cannot know a flow's own id, so this is a runtime guard plus a UI exclusion.

Settings

SettingTypeRangeNotes
Flowflow refRequired. The saved flow to call
Flow namestring≤ 200 charsDisplay cache only — calls bind to the flow id
InputslistArgument mappings: a child input name, and a value template

Argument passing

Each input mapping binds one of the child's declared Flow Inputs to a variable-aware template evaluated in the parent's scope:

Child inputValue (evaluated in the parent)
max_per_trip{{max_per_trip}}
slot_index5
target_name{{current_target}}

The evaluated values are seeded as locals of the child — true function-argument passing. The child has no knowledge of its caller, so the same child works from a queue entry, a schedule, or three different parents.

An empty or absent list means no mapping, which is valid; the child then uses its own declared defaults.

Renaming is safe

Calls bind to the flow id. Renaming the child never breaks a caller — flowName is only a display cache.

Ports

PortTaken whenRequired
SuccessThe child finalized with successYes
FailureThe child finalized with failureNo
CancelledThe child finalized with cancelledNo — never followed
FatalThe child could not be run, or recursion was detectedNo — never followed

Basic example

Extract a reusable routine:

  • Flow: Return to base
  • Inputs: none

Wire Success → carry on, Failure → recovery.

Realistic example — a thin orchestrator

The cleanest large-flow shape is a small top-level flow that does nothing but call one worker with parameters:

The orchestrator declares the Flow Inputs the operator fills in, then passes them down. Changing the strategy means editing the worker; changing the parameters means editing nothing at all.

Advanced example — a library of small functions

Decompose a large automation into single-purpose children, each with two endings:

Child flowInputsSuccess meansFailure means
Return To BaseWe are at baseCould not get there
Open Target ListList is openCould not open it
Process One Targettarget_indexHandled itSkipped or unreachable
Check CapacityRoom availableFull

The parent becomes readable at a glance:

Each child is independently testable, and the parent reads like a description of the process.

Best practices

  • Give every child exactly the endings its caller needs — usually one success and one failure, each with a message.
  • Declare inputs on the child, bind them at the call site. Never hard-code a value inside a child that a caller might want to vary.
  • Keep a child to one job you can name in a sentence.
  • Test children in isolation before wiring them into a parent.
  • Watch for repeated calls to the same child on many branches. If five paths all call "Return to base", consider restructuring so the call happens once.
  • Name children as actionsReturn To Base, Process One Target.
  • Remember maxNodeExecutions counts child nodes too. A parent calling a 20-node child 50 times executes 1000+ nodes.

Performance notes

  • The child runs inline in the same session — there is no process boundary and no parallelism. Total time is the parent's time plus every child's time.
  • Calling a child in a loop multiplies its full cost per iteration. Detection-heavy children are where this bites.
  • Sub Flow adds negligible overhead of its own; the cost is entirely the child's body.
  • Because everything is one session, a slow child blocks the whole run — decomposition is for maintainability, not speed.

Memory notes

  • The child shares the run's execution context. Bound inputs are seeded as child locals.
  • Every node the child executes is recorded in the run's nodeResults, so deep call trees in long loops grow the context steadily.
  • run-scoped Runtime Memory belongs to the run, so a child sees the same run memory as its parent.

Common mistakes

MistakeWhat happensFix
Expecting parallelismThe child runs inline, sequentiallyUse multiple instances for concurrency
Child has no failure endingThe parent cannot detect problemsGive it a failure Stop with a message
Hard-coded values inside a childNot reusableDeclare inputs, bind at the call site
Calling a flow that calls backRejected at run timeBreak the cycle
Ignoring maxNodeExecutionsRun dies mid-wayRaise the guardrail
Extracting two nodes into a childMore indirection than valueKeep it inline

Troubleshooting

The parent always takes Success even when the child clearly failed. The child's terminal node declares success. Check which Stop/Return it reached.

The child does not see its argument. The value is bound to a name the child does not declare as a Flow Input. Names must match exactly.

The node routes Fatal. The flow could not be run, or recursion was detected.

The run dies with MAX_NODE_EXECUTIONS_EXCEEDED. Child nodes count. Multiply the child's size by how often it is called.

Renaming a child broke nothing — is that right? Yes. Calls bind to the flow id.

FAQ

Does the child run in parallel with the parent? No — inline and sequential in the same session.

Can a child change the parent's variables? It receives bound inputs as its own locals. Communicate results back through its terminal status, or a shared memory scope.

Can a flow call itself? No — recursion is rejected at run time.

How deep can calls nest? Bounded in practice by maxNodeExecutions and the runtime's call-stack guard.

Is a Sub Flow's Failure port required? Only Success is required, but wiring Failure is strongly recommended.

  • Stop / Return — define the child's return value
  • Start — every child has its own
  • Loop — calling a child repeatedly
  • Variable — preparing argument values