---
title: <Parallel>
description: Run children concurrently with an optional concurrency cap.
---

```ts
import { Parallel } from "smithers-orchestrator";

type ParallelProps = {
  id?: string;
  label?: string; // display name for this group in run views (graph, /workflows mirror)
  maxConcurrency?: number; // default: no per-group cap; effective concurrency is min(this, the run-level --max-concurrency, which defaults to 4)
  subtreeConcurrency?: number; // opt-in: cap DIRECT CHILDREN (whole subtrees) in flight, not leaf tasks
  skipIf?: boolean;
  children?: ReactNode;
};
```

```tsx
<Workflow name="checks">
  <Parallel maxConcurrency={2}>
    <Task id="lint" output={outputs.lint}>
      {{ errors: 0 }}
    </Task>
    <Task id="typecheck" output={outputs.typecheck}>
      {{ passed: true }}
    </Task>
    <Task id="test" output={outputs.test}>
      {{ passed: true }}
    </Task>
  </Parallel>
</Workflow>
```

## Two concurrency semantics

`<Parallel>` supports two independent caps that may coexist:

- **`maxConcurrency` (leaf-task cap).** Caps the tasks whose *innermost*
  enclosing group is this parallel. A nested `<Parallel>` starts its own group,
  so its tasks do **not** count against the outer cap. Use it when the children
  are flat tasks (like the checks example above).
- **`subtreeConcurrency` (subtree cap, opt-in, int >= 1).** Caps how many
  **direct children** of this parallel are *in flight* at once, where every
  descendant task counts toward the child it descends from. A child is in
  flight from its first started task until all of its tasks finish; when a
  child finishes, the freed slot admits the next child in document order.
  An in-flight child may always finish its remaining tasks (even the ones in
  nested parallels) while over-cap siblings wait.

The difference matters as soon as children are subtrees. In a kanban-shaped
workflow, tickets fanned out in parallel with each ticket a sequence of
implement then reviews, `maxConcurrency={4}` neither means "4 tickets" (each ticket's
first task belongs to the outer group, but the nested review parallel escapes
it) nor bounds reviews. `subtreeConcurrency={4}` means exactly "4 tickets in
flight":

```tsx
<Workflow name="kanban">
  <Parallel id="tickets" subtreeConcurrency={2}>
    {tickets.map((ticket) => (
      <Sequence key={ticket.id} label={ticket.title}>
        <Task id={`${ticket.id}-implement`} agent={coder} output={outputs.impl}>
          Implement {ticket.title}
        </Task>
        {/* Nested parallel: 3 reviewers per ticket. Still counts toward the
            ticket's in-flight slot; its own cap bounds simultaneous reviews. */}
        <Parallel id={`${ticket.id}-reviews`} maxConcurrency={3}>
          {reviewers.map((reviewer) => (
            <Task
              key={reviewer.id}
              id={`${ticket.id}-review-${reviewer.id}`}
              agent={reviewer.agent}
              output={outputs.review}
            >
              Review the implementation of {ticket.title}
            </Task>
          ))}
        </Parallel>
      </Sequence>
    ))}
  </Parallel>
</Workflow>
```

Here at most 2 tickets are worked at once; within an active ticket at most 3
reviews run concurrently; the run-level cap still bounds total in-flight tasks.

### Subtree cap notes

- Descendant tasks record their **nearest** ancestor `<Parallel subtreeConcurrency>`:
  nesting a second subtree-capped parallel inside a child re-scopes its
  descendants to the inner group.
- Child identity is the direct child's explicit `key`/`id` prop when the
  element carries one through (e.g. `<Task id>`, `<Parallel id>`,
  `<Worktree id>`), otherwise its child ordinal. Keep direct-child order stable
  (or give ids) so resumed runs re-admit the same children.
- Admission is deterministic in document order and derived purely from task
  states, so a resumed run makes the same decisions from a restored state map.

## Notes

- Group completes when all children finish. To let the group proceed past a failing child, set `continueOnFail` on that individual child `<Task>`. It is not a `<Parallel>` prop.
- Children receive `parallelGroupId` and `parallelMaxConcurrency` in their descriptor; under a subtree cap every descendant task also receives `subtreeGroupId`, `subtreeChildKey`, and `subtreeMax`.
- A run-level cap (`bunx smithers-orchestrator up --max-concurrency, -c`, default `4`) bounds the total in-flight tasks across the whole run, applied on top of every group. So a group can never exceed it: `<Parallel>` with no cap runs at most 4 children at once, and even `<Parallel maxConcurrency={5}>` is silently truncated to 4. To fan out wider, raise `-c` (or set the run's `maxConcurrency`) as well. `subtreeConcurrency` composes the same way: leaf-group cap, subtree cap, and the run-level cap must all pass.
