---
title: <Branch>
description: Conditional fork; mounts `then` when `if` is true, otherwise `else`.
---

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

type BranchProps = {
  if: boolean;
  then: ReactElement;
  else?: ReactElement | null;
  skipIf?: boolean;
};
```

```tsx
/** @jsxImportSource smithers-orchestrator */
import { createSmithers } from "smithers-orchestrator";
import { z } from "zod";

const { Workflow, Task, Branch, smithers, outputs } = createSmithers({
  input: z.object({
    deployToProduction: z.boolean(),
  }),
  deployment: z.object({
    environment: z.enum(["staging", "production"]),
    url: z.string(),
  }),
});

export default smithers((ctx) => (
  <Workflow name="deploy-pipeline">
    <Branch
      if={ctx.input.deployToProduction}
      then={
        <Task id="deploy-production" output={outputs.deployment}>
          {{ environment: "production", url: "https://prod.example.com" }}
        </Task>
      }
      else={
        <Task id="deploy-staging" output={outputs.deployment}>
          {{ environment: "staging", url: "https://staging.example.com" }}
        </Task>
      }
    />
  </Workflow>
));
```

Use a plain boolean for `if`. The example above reads immutable run input, so
there is no stale-read hazard: `ctx.input.deployToProduction` is the same value
on every frame of that run. When the condition depends on an upstream task, read
with `ctx.outputMaybe(...)`, coalesce the missing first-frame value, and let the
render loop re-evaluate after the upstream task persists:

```tsx
const test = ctx.outputMaybe(outputs.test, { nodeId: "test" });

<Branch
  if={test?.passed === true}
  then={<Task id="deploy" output={outputs.deployment}>...</Task>}
  else={<Task id="notify" output={outputs.notification}>...</Task>}
/>
```

## Notes

- `if` re-evaluates every render frame; run input is immutable, and task outputs become visible on later frames after they persist.
- Read incomplete upstream outputs with `ctx.outputMaybe()` rather than `ctx.output()`.
- Each branch takes one element; wrap multiples in `<Sequence>` or `<Parallel>`.
- Unselected branch tasks are absent from the task graph.
- `<Branch>` takes **no children**; pass branches via `then`/`else`. Writing `<Branch>...</Branch>` throws `INVALID_INPUT` (children would otherwise be silently dropped).
