Why do LangGraph conditional edges exist when a plain DAG already has edges?
A conditional edge runs a routing function over state and returns the next node name. That is the primitive that lets a graph express cycles, branches, and retries.
Picture a board game. A normal arrow on the board says 'after square 3, always go to square 4'. Every game plays out the same way. A conditional arrow looks at the dice you just rolled and says 'if you rolled a 6, go back to start; if you rolled even, advance two; otherwise stay.' That single change turns a fixed path into a game with strategy. A flowing pipeline only has fixed arrows. An agent that decides what to do next based on what it just saw needs the dice-reading arrow. LangGraph's conditional edges are those dice-reading arrows.
Concept explanation~2 min read
Everything you need to truly understand this topic: intuition, mechanics, step by step explanation, code, formulas, and worked example. Click to expand.
Concept explanation~2 min read
Everything you need to truly understand this topic: intuition, mechanics, step by step explanation, code, formulas, and worked example. Click to expand.
A DAG framework can express every workflow that runs each node once in a fixed order. That covers data pipelines, ETL jobs, and most classical orchestration. It does not cover agents.
An agent loop alternates between thinking and acting: call the model, look at the output, decide whether to call a tool, run the tool, feed the result back to the model, repeat. The same nodes execute many times in an order that depends on what just happened. That shape requires cycles and run-time routing, and a DAG framework has neither.
LangGraph's conditional edge is the single primitive that bridges the gap. Understanding it well is the difference between a candidate who says 'LangGraph is like LangChain with state' and one who can explain why LangGraph exists as a separate package.
What a conditional edge actually is
A conditional edge has three parts: a source node, a pure function that reads state and returns a string, and a mapping from the function's return values to next-node names.
graph.add_conditional_edges(
source="agent",
path=route_fn, # state -> str
path_map={"tool": "tool_node", "done": END},
)
After the source node finishes, the runtime calls route_fn(state). The returned string is looked up in path_map to get the next node. If the mapping is omitted, the return string is used as the node name directly. END is a sentinel that terminates the run for that branch.
Situations where this technique stops working.
2–4 min · Everything important, quickly.
from langgraph.graph import StateGraph, END
def call_model(state):
response = llm.invoke(state["messages"])
return {"messages": state["messages"] + [response]}
def call_tool(state):
out = run_tool(state["messages"][-1].tool_calls[0])
return {"messages": state["messages"] + [out]}
def route(state) -> str:
last = state["messages"][-1]
return "tool" if getattr(last, "tool_calls", None) else END
graph = StateGraph(dict)
graph.add_node("model", call_model)
graph.add_node("tool", call_tool)
graph.add_edge("tool", "model") # fixed edge: tool result re-enters model
graph.add_conditional_edges("model", route) # routing function decides next step
graph.set_entry_point("model")
app = graph.compile()
Real products, models, and research that use this idea.
- LangGraph's prebuilt `create_react_agent` uses a conditional edge between the LLM node and the tool node to loop until the model emits no more tool calls
- Anthropic's research-agent reference implementation routes via conditional edges among planner, retriever, and synthesizer until coverage is sufficient
What an interviewer would ask next. Try answering before peeking at the approach.
QHow does the checkpointer interact with conditional edges during time-travel?
Walk through how each checkpoint records the node that ran and the resulting state, so forking from a checkpoint lets the route function re-evaluate against edited state and pick a different branch.
Red flags & common mistakes
The phrases that signal junior thinking. Click to expand.
Red flags & common mistakes
The phrases that signal junior thinking. Click to expand.
Treating a conditional edge as 'just an if statement'. It is the routing primitive that makes cycles legal in the graph, which is exactly what a DAG cannot express.
60 second bullets to scan on the way to the call.
Signature of a routing function and what it reads
How add_conditional_edges wires a route function to a node
Primary sources. Browse if you want the original framing.
Same topic, related formats. Practice these next.