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

# Route and branch

> Send messages down different paths: by value with BRANCH, by exit code or HTTP status, with a filter, a validation, a recipient list, or the error port.

<dl />

**Use this when** the next step depends on the message: build passed or failed, a bug or a feature. A node publishes each message on a named **output port**, and an edge listens to one port with `sourcePort`.

![A BRANCH node looks up the value in its cases; each case names an output port, an edge with that sourcePort carries the message on, and defaultPort catches the rest.](https://yukta.infenia.com/images/diagrams/guide-route-and-branch.light.svg)

The case names the port, the edge's sourcePort picks it up, and defaultPort catches everything else.

An edge with no `sourcePort` receives every port except `error`. A message on a port with no listening edge is dropped, so wire every port you care about.

## Steps

**1. Branch on a value**

`BRANCH` in its default mode `SELECT_KEY` evaluates `selector` and looks the result up in `cases`; each case names an output port. `defaultPort` catches the rest. Save as `router.json`:

```json router.json theme={"system"}
{
  "sessionId": "router",
  "name": "Router",
  "description": "Sort tickets by kind",
  "initiator": "docs",
  "projectPath": "/tmp",
  "workflows": {
    "sort": {
      "workflowId": "sort",
      "description": "Bugs, features and the rest",
      "nodes": [
        { "nodeId": "ticket", "type": "API_TRIGGER", "config": {} },
        { "nodeId": "by-kind", "type": "BRANCH",
          "config": { "selector": "payload.kind",
                      "cases": { "bug": "bug-queue", "feature": "feature-queue" },
                      "defaultPort": "other-queue" } },
        { "nodeId": "bugs", "type": "CONSOLE_TERMINAL", "config": {} },
        { "nodeId": "features", "type": "CONSOLE_TERMINAL", "config": {} },
        { "nodeId": "other", "type": "CONSOLE_TERMINAL", "config": {} }
      ],
      "edges": [
        { "source": "ticket", "target": "by-kind" },
        { "source": "by-kind", "target": "bugs", "sourcePort": "bug-queue" },
        { "source": "by-kind", "target": "features", "sourcePort": "feature-queue" },
        { "source": "by-kind", "target": "other", "sourcePort": "other-queue" }
      ]
    }
  }
}
```

```bash theme={"system"}
curl -X POST localhost:9858/api/sessions -H 'Content-Type: application/json' -d @router.json
curl -s -X POST localhost:9858/api/workflow/start -H 'Content-Type: application/json' \
  -d '{"sessionId":"router","workflowId":"sort","payload":{"kind":"bug"}}'
```

The ports are the distinct values of `cases`, plus `defaultPort`. A case that routes to a port with no outgoing edge fails validation.

**2. Branch on a condition instead**

With `mode: EXPRESSION`, each case key is a predicate and the first one that is true names the port:

```json theme={"system"}
{ "nodeId": "decide", "type": "BRANCH",
  "config": { "mode": "EXPRESSION",
              "cases": { "payload.coverage < 80 || payload.lintErrors > 0": "fail" },
              "defaultPort": "pass" } }
```

The syntax is in the [Expressions reference](https://yukta.infenia.com/reference/expressions.md). With `strictMode` on (the default) a message that matches nothing and has no `defaultPort` fails the node; `allowMultipleMatches` emits on every matching case.

**3. Route on how a command or request went**

`PROCESS_EXECUTOR` with `"failureMode": "CONTINUE", "routeByExitCode": true` leaves on `success` or `failure`; `HTTP_REQUEST` does the same with `"routeByStatus": true`. Wire `"sourcePort": "success"` and `"failure"`.

**4. Filter, validate, fan out**

* `FILTER` passes messages that match `condition` and drops the rest.
* `VALIDATE` sends messages that fail to its `invalid` port.
* `RECIPIENT_LIST` sends one message to several recipients, each recipient a port, optionally in parallel.
* To send the **same** message to several nodes without choosing, give the node several edges without `sourcePort`: every child receives every message.

**5. Route failures and rejoin branches**

With `"onError": "ROUTE"` in a node's `engine` object, a message that fails all its attempts leaves on the `error` port: `{ "source": "classify", "target": "dead-letter", "sourcePort": "error" }`. See [Handle failures](https://yukta.infenia.com/guides/build/handle-failures.md). Several branches may lead into one node; when it has several parents its `engine.trigger` join rule decides what a failed branch means.

## Verify it worked

```bash theme={"system"}
curl -s -H 'Accept: application/json' localhost:9858/api/sessions/router/executions/$EXEC/results
```

The `RESULT` event comes from node `bugs`. Start again with `"kind":"idea"` and it comes from `other`. To check the wiring before running, validate the workflow: the answer lists each node's output ports ([Validate and roll back](https://yukta.infenia.com/guides/build/validate-and-roll-back.md)).

## Variations

* **Exact options for every routing plugin.** [Routing and flow reference](https://yukta.infenia.com/reference/plugins/routing-and-flow.md).
* **Route on an AI decision.** `CLASSIFY` writes its choice to a port: [Classify, gate and score](https://yukta.infenia.com/guides/ai/classify-gate-and-score.md).

## Related

* [How Yukta works](https://yukta.infenia.com/concepts/how-it-works.md) for nodes, edges and ports.
* [Failure model](https://yukta.infenia.com/concepts/failure-model.md) for join rules and error routes.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.