LangGraphLangGraph 1.2 · Python 3.10+
0%
1
Curious builder0 XP earned · 300 to level 2
0 daysFinish a lesson to begin
Badge collection0 of 6 unlocked
38 small wins to finish your pathNext lesson →

Conditional edges: choosing a path

A conditional edge lets the graph look at the state and choose which node runs next: add_conditional_edges(source, router, targets) calls your router function and goes where it returns.

Last updated: 27 Sep, 2026 · LangGraph 1.2

So far every run goes the same way. But a billing complaint and a crash report should not get the same reply, and junk mail should get none at all. That is three outcomes from one starting point.

The add_conditional_edges call

python
def router(state):
    return "node_name"   # a node name to go there, or END to stop

builder.add_conditional_edges(source, router, ["node_a", "node_b", END])

The state

Start with the imports and the state. The state holds the incoming ticket and the reply a node will write back.

python
from typing_extensions import TypedDict
from langgraph.graph import StateGraph, START, END

class State(TypedDict):
    ticket: str   # the incoming message
    reply: str    # the answer a node writes

The handler nodes

Add two handler nodes, one per team. Each returns a fixed reply for now.

python
def billing(state):
    return {"reply": "We will refund the double charge."}

def technical(state):
    return {"reply": "Try logging out and back in."}

The router function

Here is the new idea. pick_team reads the ticket and returns where to go next: a node name, or END to stop. It is a plain function, not a node, so it is never added with add_node.

python
def pick_team(state):
    if "win a prize" in state["ticket"]:   # junk mail
        return END                         # stop, no reply
    # a charge goes to billing, anything else to technical
    return "billing" if "charge" in state["ticket"] else "technical"

Wiring the router

Wire the two nodes, then attach the router to START with add_conditional_edges. The list at the end names every place the router might send the run.

python
builder = StateGraph(State)
builder.add_node("billing", billing)
builder.add_node("technical", technical)
builder.add_conditional_edges(START, pick_team, ["billing", "technical", END])  # router picks the path
graph = builder.compile()

Running three tickets

Run three tickets through the same graph and print each reply.

python
for ticket in ["charged twice", "app will not open", "win a prize now"]:
    print(repr(graph.invoke({"ticket": ticket, "reply": ""})["reply"]))

Three tickets, three paths

The same pieces in one file, ready to run.

Example
from typing_extensions import TypedDict
from langgraph.graph import StateGraph, START, END

class State(TypedDict):
    ticket: str
    reply: str

def billing(state):
    return {"reply": "We will refund the double charge."}

def technical(state):
    return {"reply": "Try logging out and back in."}

def pick_team(state):
    if "win a prize" in state["ticket"]:
        return END
    return "billing" if "charge" in state["ticket"] else "technical"

builder = StateGraph(State)
builder.add_node("billing", billing)
builder.add_node("technical", technical)
builder.add_conditional_edges(START, pick_team, ["billing", "technical", END])
graph = builder.compile()

for ticket in ["charged twice", "app will not open", "win a prize now"]:
    print(repr(graph.invoke({"ticket": ticket, "reply": ""})["reply"]))

Why each ticket went where it did

  • pick_team is a function but not a node: it is never added with add_node, and it returns a destination, not a state update.
  • Returning a string sends the run to the node with that name; returning END stops it.
  • The third ticket gets an empty reply because pick_team sent it straight to END and neither reply node ran.

What the router may return

Router returnsWhat happens
"billing"The billing node runs next
ENDThe run stops with no further node
A value in the path_mapMaps to the node the map names
True / the ticketError, unless it is a key in the path_map

When to branch on the state

  • Routing a request by its intent (billing vs technical vs spam).
  • Skipping steps that do not apply, or ending a run early.
Watch out. A router must return a string matching a node name, or END, or a key present in the optional path_map. Returning the ticket or True with no map is the first mistake.
Try it yourself
  • Add a general node and route tickets that match neither rule to it.
  • Make pick_team return True with no path_map and read the error.
  • Route a fourth ticket, "refund my charge", and predict the path before running.

You understood something today that you didn't yesterday.