import { Callout, Cards, Tabs } from "nextra/components";
import UniversalTabs from "@/components/UniversalTabs";
import { Snippet } from "@/components/code";
import { snippets } from "@/lib/generated/snippets";
import CycleDiagram from "@/components/CycleDiagramWrapper";
import BatchProcessingDiagram from "@/components/BatchProcessingDiagramWrapper";
import FanoutDiagram from "@/components/FanoutDiagram";

# Child Spawning

A task can spawn child tasks at runtime — including other durable tasks or entire DAG workflows. Children run independently on any available worker, and the parent can wait for their results before continuing. You can spawn children out of any task (durable or not).

<Callout type="info">
  While child spawning is not unique to durable tasks, we often recommend using
  durable tasks when spawning children is the main responsibility (or one of the
  main responsibilities) of a task. For instance, an agent might spawn many
  children (i.e. tool calls) as its main responsibility, making a durable task a
  good fit.
</Callout>

### Spawning a child task

You can spawn child tasks similarly to how you run tasks normally, but the implementation details differ slightly by language. Any task can spawn child tasks.

<UniversalTabs items={["Python", "Typescript", "Go", "Ruby"]}>
<Tabs.Tab title="Python">

<Snippet src={snippets.python.fanout.example_child_spawn.child_spawn} />

</Tabs.Tab>
<Tabs.Tab title="Typescript">

<Snippet
  src={snippets.typescript.child_workflows.workflow.parent_with_single_child}
/>

</Tabs.Tab>
<Tabs.Tab title="Go">

<Snippet src={snippets.go.child_workflows.main.spawning_a_child_workflow} />

</Tabs.Tab>
  <Tabs.Tab title="Ruby">
    <Snippet src={snippets.ruby.fanout.example_child_spawn.child_spawn} />
  </Tabs.Tab>
</UniversalTabs>

### Spawning many children at once

You can also spawn children in bulk, exactly the same as you can spawn any other tasks in bulk.

<UniversalTabs items={["Python", "Typescript", "Go", "Ruby"]} variant="hidden">
<Tabs.Tab title="Python">

<Snippet src={snippets.python.fanout.trigger.bulk_run_children} />

</Tabs.Tab>
<Tabs.Tab title="Typescript">

<Snippet
  src={snippets.typescript.child_workflows.workflow.declaring_a_parent}
/>

</Tabs.Tab>
<Tabs.Tab title="Go">

<Snippet src={snippets.go.child_workflows.main.parallel_child_task_execution} />

</Tabs.Tab>
  <Tabs.Tab title="Ruby">
    <Snippet src={snippets.ruby.fanout.trigger.bulk_run_children} />
  </Tabs.Tab>
</UniversalTabs>

### What you can spawn

A durable task can spawn any runnable:

| Child type       | Example                                                                           |
| ---------------- | --------------------------------------------------------------------------------- |
| **Regular task** | Spawn a stateless task for a quick computation or API call.                       |
| **Durable task** | Spawn another durable task that has its own checkpoints, sleeps, and event waits. |
| **DAG workflow** | Spawn an entire multi-task workflow and wait for its final output.                |

### Error handling

<UniversalTabs items={["Python", "Typescript", "Go", "Ruby"]} variant="hidden">
<Tabs.Tab title="Python">

<Snippet src={snippets.python.fanout.example_child_spawn.error_handling} />

</Tabs.Tab>
<Tabs.Tab title="Typescript">

<Snippet
  src={snippets.typescript.child_workflows.workflow.parent_with_error_handling}
/>

</Tabs.Tab>
<Tabs.Tab title="Go">

<Snippet src={snippets.go.child_workflows.main.error_handling} />

</Tabs.Tab>
  <Tabs.Tab title="Ruby">
    <Snippet src={snippets.ruby.fanout.example_child_spawn.error_handling} />
  </Tabs.Tab>
</UniversalTabs>

## Ways to use child spawning

### Fan-out: spawning many children in parallel

Process a list of items whose length is only known at runtime. Spawn one child per item, collect all results, then continue. Document processing and batch processing are the canonical examples: when a batch of files arrives, a parent fans out to one child per document; each child parses, extracts, and validates its document in parallel across your worker fleet.

<BatchProcessingDiagram />

[Concurrency](/v1/concurrency) controls how many children run at once. Hatchet distributes child tasks across available workers, so adding workers increases throughput without code changes. For rate-limited external services (OCR, LLM APIs), combine with [Rate Limits](/v1/rate-limits) to throttle child execution across all workers.

### Agent reasoning loops

An agent loop runs by having a durable task spawn a new child run of itself with updated input until a termination condition is met. Each iteration is a separate child task, so you get full observability in the dashboard. AI agents use this when they reason about what to do next, spawn a subtask (or a sub-workflow), inspect the result, and decide whether to continue, branch, or stop.

<CycleDiagram />

### Spawning trees of work

A durable task can spawn child durable tasks, each of which may spawn their own children. This creates a tree of work that's entirely driven by runtime logic — useful for crawlers, recursive search, and tree-structured computations.

<Snippet src={snippets.go.child_workflows.main.spawning_a_child_workflow} />
