Docs
Reference

Step Fanout (:fanout)

Quick Answer

Use :fanout when you need a bounded batch of child workflows that start now and collect later.
Async fanout is available when every item is {:type :call-flow ...} or every item is {:type :agent ...}.
Legacy non-child fanout items are still accepted for backward compatibility, but they run on the sequential compatibility path.

Use for bounded child-workflow spawn/collect, not as a general parallel side-effect primitive.

Canonical Shape

Core fields:

FieldTypeRequiredNotes
:typekeywordYesUse :fanout
:itemsvectorYesRuntime width is bounded to 25 items
:max-concurrencyintNoRequested width for async child fanout; must be 1-20
:on-errorkeyword/stringNo:fail (default), :continue, or :collect
:transformformNoSCI transform over the aggregated result map

Async child-flow items:

Item fieldTypeRequiredNotes
:typekeywordYesMust be :call-flow for async child fanout
:flow-slugkeyword/stringYesChild flow to start
:inputanyNoChild input payload
:timeoutintNoMapped to child workflow timeout fields
:versionintNoOptional child version override
:installation-idstringNoOptional child installation/live target override
:workflow-idstringNoOptional explicit child workflow id
:parent-close-policykeyword/stringNo:abandon, :request-cancel, or :terminate
:retry-policymapNoOptional child retry override

:profile-id is still accepted as a compatibility alias for async child-workflow
items, but new source should use :installation-id for target-specific child
runs.

Async agent items:

Item fieldTypeRequiredNotes
:typekeywordYesMust be :agent for named-agent fanout
:agent / :agent-idqualified keyword/stringYesReference to a top-level flow :agents definition to run, for example :review/security
:inputmapNoInvocation config passed to the agent. Overlay keys inside this map override the agent definition.
:inputsmapNoCompatibility alias for :input
:step-idkeyword/stringNoOptional child step id; generated from the parent fanout step and item index when omitted
:timeoutintNoMapped to child workflow timeout fields
:versionintNoOptional parent-flow version override for the agent child run
:installation-idstringNoOptional live target override
:workflow-idstringNoOptional explicit child workflow id
:parent-close-policykeyword/stringNo:abandon, :request-cancel, or :terminate
:retry-policymapNoOptional child retry override

Child-Workflow Mode

Async :fanout is enabled only when all items use one child-workflow mode:
all :call-flow items, or all :agent items.
In that mode, Breyta:

  • starts children up to the effective concurrency cap
  • waits until child start is confirmed before counting the child as spawned
  • collects results later while preserving the original item order
  • records fanout lineage on child executions (:root-workflow-id, :parent-workflow-id, :fanout-depth, :fanout-parent-step-id, :fanout-max-concurrency)
  • inherits draft child version 0 when the parent is running from draft and the item does not specify :version, :installation-id, or live target context
  • treats an explicit child :version as a versioned child execution; run lists
    show the child lineage fields so you can distinguish these from direct manual
    live runs
  • for :agent items, starts a child workflow for the current parent flow and
    runs only the selected flow-level agent entrypoint

For :agent fanout, keep the reusable agent configuration in top-level
:agents; the fanout item only references it with :agent or :agent-id.
Do not put the full agent configuration inside :items.
If a coordinator agent should decide which sibling specialists to run while
reasoning, prefer the agent-internal :tools {:fanout ...} surface. Use this
flow-level step when :flow already has the deterministic item list. See
Orchestration Agent Fanout.

Child-flow example:

(flow/step :fanout :spawn-children
           {:items [{:type :call-flow
                     :flow-slug :billing-apply
                     :input {:invoice-id "inv-1"}}
                    {:type :call-flow
                     :flow-slug :billing-apply
                     :input {:invoice-id "inv-2"}}]
            :max-concurrency 5
            :on-error :collect})

Agent fanout example:

(flow/step :fanout :parallel-review
           {:items [{:type :agent
                     :agent :review/security
                     :input {:area "auth" :repo-tree repo-tree}}
                    {:type :agent
                     :agent :review/performance
                     :input {:area "queries" :repo-tree repo-tree}}]
            :max-concurrency 2
            :on-error :collect})

Typical parent-flow pattern:

'(let [input (flow/input)
       fanout (flow/step :fanout :spawn-children
                         {:items (:items input)
                          :max-concurrency 5
                          :on-error :collect})]
   {:item-count (count (:items input))
    :fanout fanout})

Legacy Compatibility Mode

Legacy fanout items are still accepted for these step types:

  • :http
  • :llm
  • :notify
  • :function
  • :code

That mode is kept for compatibility only.
It executes deterministically in a loop, even if :max-concurrency is provided.
For new orchestration, prefer explicit loops or child workflows instead of adding new legacy fanout usage.

Result Shape

Default return shape:

{:successes [{:item ... :result ...}]
 :failures [{:item ... :error ...}]
 :total N
 :success-count N
 :failure-count N}

When :transform is set, the transform receives:

{:successes [...]
 :failures [...]
 :total N
 :success-count N
 :failure-count N
 :items [...]}

Guardrails And Limits

  • Async fanout supports only :call-flow items or named :agent items.
  • Do not mix legacy step items, :call-flow items, and :agent items in one :fanout.
  • Nested :fanout items are rejected.
  • Nested async child fanout is rejected beyond one level.
  • :max-concurrency must be at most 20; validation rejects larger values.
  • One :fanout step can include at most 25 items.
  • One root run can start at most 25 child workflows total.
  • One run can execute at most 5 fanout steps and 100 total fanout items across those steps.

For child flows that can produce large outputs, persist large artifacts inside the child flow and return compact refs or summaries.
Collected fanout results are still subject to inline result limits.

Related

As of Jun 11, 2026