> ## Documentation Index
> Fetch the complete documentation index at: https://learn.workflow.dog/llms.txt
> Use this file to discover all available pages before exploring further.

# Build Sub-Workflows

> Extract reusable workflow logic, define its input and output, and call it safely.

A sub-workflow packages a reusable sequence behind one input and one returned
value. It can be called from another workflow, used as the body of a loop, or
used as a custom list predicate.

## The callable workflow contract

A callable workflow has three parts:

```text theme={null}
Sub-Workflow trigger
  → Data from Trigger: Data In
  → reusable actions
  → Return Data: Data Out
```

* The [Sub-Workflow trigger](/reference/triggers/core/callable) allows another
  workflow to start it.
* [Data from Trigger](/reference/actions/core/trigger-data) exposes the
  caller's payload as **Data In**.
* [Return Data](/reference/actions/core/return-data) sends one value back to a
  waiting caller.

The input and output can be any supported value. For a stable interface,
prefer an object with named properties over a positional list or an
undocumented block of text.

## Create one manually

<Steps>
  <Step title="Create the workflow">
    Choose **When another workflow calls this one** as its trigger.
  </Step>

  <Step title="Read Data In">
    Add **Data from Trigger** and connect **Data In** to the actions that need
    the caller's payload.
  </Step>

  <Step title="Perform the work">
    Add validation, integrations, and transformations as you would in any
    workflow.
  </Step>

  <Step title="Return Data Out">
    Add **Return Data** and connect the result. A waiting caller receives `null`
    if the child finishes without returning data.
  </Step>

  <Step title="Call the workflow">
    Add [Run Workflow](/reference/actions/core/run-workflow) to the parent,
    select the child, and connect its payload.
  </Step>
</Steps>

## Call once

[Run Workflow](/reference/actions/core/run-workflow) starts the selected
callable workflow and waits for it to finish.

| Parent input or output | Child meaning                                               |
| ---------------------- | ----------------------------------------------------------- |
| **Payload**            | Becomes **Data In**.                                        |
| **Result**             | Receives the value sent through **Return Data**, or `null`. |

If the child fails, Run Workflow fails with the child's failure message. This
makes validation and errors in the child visible to the parent.

## Call for a list

Use [Loop Workflow](/reference/actions/core/loop-workflow) when the same child
should process multiple payloads. It starts one child at a time and returns one
result per item in the same order.

Custom list predicates use the same interface:

* [Filter With Workflow](/reference/actions/arrays/filter-with-workflow) keeps
  items whose child returns a truthy value.
* [Find With Workflow](/reference/actions/arrays/find-with-workflow) returns
  the first item whose child returns a truthy value.

See [Lists and Loops](/building/lists-and-loops) for the behavioral differences
and limits.

## Select a workflow dynamically

The **Selected Workflow** input can be fixed in the node or supplied as a
Workflow value. [Workflow](/reference/actions/core/workflow) resolves a
callable workflow from the current project and exposes that typed value.

Dynamic selection is useful when an earlier branch chooses among several
implementations with the same input/output contract. Keep the contract
consistent; the editor cannot prove that two arbitrary workflows return the
same shape.

## Extract selected nodes

The canvas can turn an existing selection into a sub-workflow:

<Steps>
  <Step title="Select the reusable section">
    Select the connected actions you want to move.
  </Step>

  <Step title="Choose Extract to Sub-Workflow">
    The editor creates and enables a callable workflow, moves the selected
    actions into it, and adds a configured **Run Workflow** node in their place.
  </Step>

  <Step title="Inspect the boundary">
    When the selection has exactly one connection entering and one leaving, the
    editor bridges them through the new payload and result.
  </Step>

  <Step title="Name and document the contract">
    Rename the new workflow and add a [Comment](/reference/actions/core/comment)
    describing its expected input, returned output, and failure behavior.
  </Step>
</Steps>

<Warning>
  Review extracted workflows before relying on them. Selections with multiple
  inbound or outbound boundary connections cannot be represented by one
  automatic payload or result connection. Package multiple values into an object
  before extraction, or reconnect the interface manually afterward.
</Warning>

## Design a durable contract

Use an object for any interface likely to grow:

```json theme={null}
{
  "customer_id": "cus_123",
  "order_id": "ord_456",
  "notify": true
}
```

Return a similarly named object:

```json theme={null}
{
  "status": "processed",
  "record_id": "rec_789"
}
```

This makes call sites self-describing and lets you add optional properties
without changing the meaning of existing positions.

## Failure and recursion behavior

* A failure propagates through callers that wait, including **Run Workflow**,
  **Loop Workflow**, and workflow-backed filter/find actions.
* A child with no **Return Data** produces `null`; that is a successful run,
  not a failure.
* Loop and predicate callers fail rather than returning partial results when a
  child fails.
* Recursive workflow calls are rate-limited to prevent infinite recursion.

<Tip>
  Put reusable business logic in a sub-workflow, but leave orchestration in the
  parent. A focused child with a clear input, output, and error contract is
  easier to test and reuse than a large child that controls the entire process.
</Tip>
