LangGraph/Control Flow
Intermediate14 min

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.

Update state while routing?node writes to state AND picks next nodeYESNOCommandgoto + updateNext node always the same?same destination every timeYESNOadd_edgefixed pathFan-out count known at build?fixed set of destination nodesYESNOadd_conditional_edgesdynamic, finite routesSenddynamic fan-out

Choose the right edge primitive — wrong choice means lost state updates or unnecessary complexity

PrimitiveWhen to useWhat it can do
add_edgeDestination is always the same nodeRoute only — no state change
add_conditional_edgesDestination depends on state, set of destinations is fixed at build timeRoute only — no state change
CommandDestination depends on state AND the node must also update stateRoute + atomic state update
SendFan-out to N nodes in parallel, where N may not be known at build timeRoute to multiple nodes with per-branch state
Command adds dynamic edges on top of static ones

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.