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 →

Command: update and route in one step

A Command lets a node do two things at once: change the state and choose the next node. Return Command(update={...}, goto="...") instead of a plain dict.

Last updated: 27 Sep, 2026 · LangGraph 1.2

With a conditional edge, one function decides the state and a separate function decides the route. When the node already knows both, a Command carries them together and you skip the router.

The Command return

python
from langgraph.types import Command
from typing import Literal

def node_a(state) -> Command[Literal["node_b"]]:
    return Command(update={"key": "value"}, goto="node_b")

The state

Start with the imports and a one-key state. Command comes from langgraph.types.

python
from typing import Literal
from typing_extensions import TypedDict
from langgraph.types import Command
from langgraph.graph import StateGraph, START, END

class State(TypedDict):
    foo: str

The Command node

Here is the new idea. node_a returns a Command instead of a plain dict: update changes the state and goto names the next node. The Command[Literal["node_b"]] annotation tells LangGraph where this node can go.

python
def node_a(state) -> Command[Literal["node_b"]]:
    # update the state AND choose the next node in one return
    return Command(update={"foo": "bar"}, goto="node_b")

Wiring and running

Wire the graph. There is no router after node_a, because its goto already carries the route. node_b reads the updated foo and adds an exclamation mark.

python
builder = StateGraph(State)
builder.add_node("node_a", node_a)
builder.add_node("node_b", lambda s: {"foo": s["foo"] + "!"})  # reads foo, adds "!"
builder.add_edge(START, "node_a")   # no conditional edge after node_a
builder.add_edge("node_b", END)

print(builder.compile().invoke({"foo": ""}))

Update and route in one node

The same pieces in one file, ready to run.

Example
from typing import Literal
from typing_extensions import TypedDict
from langgraph.types import Command
from langgraph.graph import StateGraph, START, END

class State(TypedDict):
    foo: str

def node_a(state) -> Command[Literal["node_b"]]:
    return Command(update={"foo": "bar"}, goto="node_b")

builder = StateGraph(State)
builder.add_node("node_a", node_a)
builder.add_node("node_b", lambda s: {"foo": s["foo"] + "!"})
builder.add_edge(START, "node_a")
builder.add_edge("node_b", END)

print(builder.compile().invoke({"foo": ""}))

What node_a did in one return

  • node_a set foo to "bar" and sent the run to node_b in one return, with no conditional edge after it.
  • node_b read the updated foo and added "!", giving "bar!".
  • The Command[Literal["node_b"]] annotation tells LangGraph where this node can go, which also lets it draw the graph.

Command vs a conditional edge

Conditional edgeCommand
Who decides the routeA separate router functionThe node itself
Who updates the stateThe nodeThe same node, in the Command
Reach for it whenRouting logic is shared or complexThe node already knows the update and the next step

When a node knows both

  • A classifier that both records the category and jumps to the matching handler.
  • Any node whose result also decides where the run goes next.
Watch out. goto must name a real node or END. Import Command from langgraph.types, not langgraph.graph.
Try it yourself
  • Add a node_c and make node_a choose between node_b and node_c from the state.
  • Return a plain dict from node_a instead and wire a normal edge. Same result?

Every expert started right here.