Subgraph definition and purpose
A subgraph is a graph that is used as a node in another graph. Subgraphs are useful for building multi-agent systems, reusing a set of nodes in multiple graphs, and distributing development so different teams can work on different parts of the graph independently while respecting the subgraph interface (input and output schemas).
Two patterns for subgraph communication
When adding subgraphs, two communication patterns exist: (1) Call a subgraph inside a node when parent and subgraph have different state schemas with no shared keys, or need to transform state between them—you write a wrapper function that maps parent state to subgraph input and back. (2) Add a subgraph as a node when parent and subgraph share state keys—the subgraph reads from and writes to the same channels as the parent, requiring no wrapper function.
Call subgraph inside node with state transformation
When parent and subgraph have different state schemas, invoke the subgraph inside a node function. The node function transforms parent state to subgraph state before invoking the subgraph via subgraph.invoke(), and transforms the results back to parent state before returning. This pattern is common when keeping a private message history for each agent in a multi-agent system.
Add compiled subgraph directly as node
When parent and subgraph share state keys, pass a compiled subgraph directly to add_node() with no wrapper function needed. The subgraph automatically reads from and writes to the parent's state channels. This pattern is used in multi-agent systems where agents communicate over a shared messages key.
Stream subgraph outputs with subgraphs projection
To observe nested graph executions, use event streaming with stream.subgraphs projection: graph.stream_events({...}, version='v3') returns a stream with subgraph outputs discovered and exposed with path, messages, and values without parsing namespace strings. For raw protocol events, iterate stream directly and filter on event['method'] and event['params']['namespace'].
Subgraph state schema isolation
Each subgraph can have its own private state keys not visible to parent or sibling subgraphs. When a subgraph has a state schema with keys (like 'bar', 'baz'), only those keys are accessible within the subgraph. Parent or grandchild keys are not accessible. This enables modular design where each subgraph has isolated internal state.
Nested subgraphs example
LangGraph supports multiple levels of subgraphs (parent → child → grandchild). Each level can call the next level via wrapper functions that transform state at graph boundaries. Namespace paths in stream events show the nesting hierarchy as a list (e.g., ['child:uuid', 'child_1:uuid']).
Example: Call subgraph inside node with different state schemas (Python)
from typing_extensions import TypedDict
from langgraph.graph.state import StateGraph, START
class SubgraphState(TypedDict):
bar: str
def subgraph_node_1(state: SubgraphState):
return {"bar": "hi! " + state["bar"]}
subgraph_builder = StateGraph(SubgraphState)
subgraph_builder.add_node(subgraph_node_1)
subgraph_builder.add_edge(START, "subgraph_node_1")
subgraph = subgraph_builder.compile()
class State(TypedDict):
foo: str
def call_subgraph(state: State):
subgraph_output = subgraph.invoke({"bar": state["foo"]})
return {"foo": subgraph_output["bar"]}
builder = StateGraph(State)
builder.add_node("node_1", call_subgraph)
builder.add_edge(START, "node_1")
graph = builder.compile()
Example: Add subgraph as node with shared state schemas (Python)
from typing_extensions import TypedDict
from langgraph.graph.state import StateGraph, START
class State(TypedDict):
foo: str
def subgraph_node_1(state: State):
return {"foo": "hi! " + state["foo"]}
subgraph_builder = StateGraph(State)
subgraph_builder.add_node(subgraph_node_1)
subgraph_builder.add_edge(START, "subgraph_node_1")
subgraph = subgraph_builder.compile()
builder = StateGraph(State)
builder.add_node("node_1", subgraph)
builder.add_edge(START, "node_1")
graph = builder.compile()
Example: Per-invocation subgraph with interrupts and multi-agent (Python)
from langchain.agents import create_agent
from langchain.tools import tool
from langgraph.checkpoint.memory import MemorySaver
@tool
def fruit_info(fruit_name: str) -> str:
"""Look up fruit info."""
return f"Info about {fruit_name}"
fruit_agent = create_agent(
model="gpt-5.4-mini",
tools=[fruit_info],
prompt="You are a fruit expert. Use the fruit_info tool. Respond in one sentence.",
)
@tool
def ask_fruit_expert(question: str) -> str:
"""Ask the fruit expert. Use for ALL fruit questions."""
response = fruit_agent.invoke(
{"messages": [{"role": "user", "content": question}]},
)
return response["messages"][-1].content
agent = create_agent(
model="gpt-5.4-mini",
tools=[ask_fruit_expert],
prompt="You have a fruit expert. ALWAYS delegate fruit questions to ask_fruit_expert.",
checkpointer=MemorySaver(),
)
Example: Stream subgraph events (Python)
from typing_extensions import TypedDict
from langgraph.graph.state import StateGraph, START
class SubgraphState(TypedDict):
foo: str
bar: str
def subgraph_node_1(state: SubgraphState):
return {"bar": "bar"}
def subgraph_node_2(state: SubgraphState):
return {"foo": state["foo"] + state["bar"]}
subgraph_builder = StateGraph(SubgraphState)
subgraph_builder.add_node(subgraph_node_1)
subgraph_builder.add_node(subgraph_node_2)
subgraph_builder.add_edge(START, "subgraph_node_1")
subgraph_builder.add_edge("subgraph_node_1", "subgraph_node_2")
subgraph = subgraph_builder.compile()
class ParentState(TypedDict):
foo: str
def node_1(state: ParentState):
return {"foo": "hi! " + state["foo"]}
builder = StateGraph(ParentState)
builder.add_node("node_1", node_1)
builder.add_node("node_2", subgraph)
builder.add_edge(START, "node_1")
builder.add_edge("node_1", "node_2")
graph = builder.compile()
stream = graph.stream_events({"foo": "foo"}, version="v3")
for event in stream:
if event["method"] == "updates":
print(event["params"]["namespace"], event["params"]["data"])
Message streaming from subgraph events option
Agent server v0.4.46 added an option to enable message streaming from subgraph events, giving users more control over event notifications.
Navigate to parent graph nodes with Command.PARENT
When using subgraphs, specify graph=Command.PARENT in Command to navigate from a subgraph node to a node in the parent graph. Example: Command(update={'foo': 'bar'}, goto='other_subgraph', graph=Command.PARENT). This navigates to the closest parent graph relative to the subgraph.
Reducers required for Command.PARENT state updates
When updating state from a subgraph node via Command.PARENT for shared state keys, you must define a reducer for that key in the parent graph state. Example: foo: Annotated[str, operator.add]. Without reducers, state updates may be lost.