Intermediate14 min
Edges & Routing
LangGraph has four edge primitives — add_edge, add_conditional_edges, Command, and Send. Picking the wrong one means lost state updates, infinite loops, or fan-out patterns that silently misbehave.
Quick Reference
- →add_edge(src, dst): unconditional — always goes src → dst regardless of state
- →add_conditional_edges(src, fn, path_map): fn reads state and returns a key that maps to a node
- →Command(goto='node', update={...}): node returns this to route AND update state in one step
- →Send('node', state): return from conditional edge to fan out to N copies of a node with custom state
- →Multiple outgoing edges run in parallel in the next superstep — all destinations execute before the graph advances
- →recursion_limit default is 25 — every cycle counts against it; configure via graph.compile(recursion_limit=N)
- →Command does NOT override add_edge — if both exist on the same node, both destinations execute
- →path_map is optional — use Literal type hints on route_fn return type instead for the same validation
Which Edge Primitive Do You Need?
Before writing any edges, pick the right primitive. Using add_conditional_edges when you need Command means writing a separate routing function for something the node already knows. Using Command when you need Send means hardcoding fan-out count that should be dynamic.
Choose the right edge primitive — wrong choice means lost state updates or unnecessary complexity
| Primitive | When to use | State update? | Fan-out |
|---|---|---|---|
| add_edge | Next node is always the same | No | 1 fixed |
| add_conditional_edges | Next node depends on state, but node doesn't update state while routing | No | N fixed |
| Command | Node knows where to go AND needs to update state in the same step | Yes | N fixed |
| Send | Fan-out count is unknown at graph-build time (map-reduce) | Custom per-send | N dynamic |