Branching & Conditional Routing
LangGraph gives you four routing primitives — add_edge, add_conditional_edges, Command, and Send — each for a distinct scenario. This article teaches you when to use which one, how to build LLM-powered routers with real cost math, and what failure modes to design against before you ship.
Quick Reference
- →add_conditional_edges(source, fn, path_map): routing only — the function inspects state and returns the name of the next node. State is not changed here.
- →Command(goto='node', update={...}): routing + state update atomically — the node returns a Command instead of a dict. Use when the routing decision and state mutation must happen together.
- →Send(node_name, state): dynamic fan-out — returns a list of Send objects from a conditional edge to dispatch the same or different state to N nodes in parallel.
- →Confidence threshold: always add a confidence field to your routing schema and fall back to a safe default when confidence < 0.70.
- →Reducers are required for parallel merge: use Annotated[list[str], operator.add] on any state key that parallel Send() branches write to — without it, the last writer wins silently.
- →gpt-5.4-nano pricing: ~$0.20/1M input, ~$1.25/1M output. A 300-token routing call costs about $0.0001 — routing cost is negligible compared to handler cost.
- →RemainingSteps: declare it as a managed value in state to detect recursion headroom. Route to a graceful fallback when remaining_steps < 3.
Which Routing Primitive?
LangGraph has four ways to move between nodes. Picking the wrong one wastes code or, worse, silently drops state updates. The decision is simpler than it looks: one question about state mutation, one about destination count.
Choose the right edge primitive — wrong choice means lost state updates or unnecessary complexity
| Primitive | When to use | What it can do |
|---|---|---|
| add_edge | Destination is always the same node | Route only — no state change |
| add_conditional_edges | Destination depends on state, set of destinations is fixed at build time | Route only — no state change |
| Command | Destination depends on state AND the node must also update state | Route + atomic state update |
| Send | Fan-out to N nodes in parallel, where N may not be known at build time | Route to multiple nodes with per-branch state |
If you use both add_edge(source, dest) and have the source node return Command(goto='other'), both dest and other will execute. Static edges still fire. Keep either add_edge or Command on a given node, not both.