Subgraphs

LangGraph · Advanced · 13 min

Subgraphs let teams build, test and reuse pieces of a large agent system independently.

A subgraph is a compiled graph used inside another graph. There are two ways to connect one.

Add it directly as a node when parent and child share state keys: parent.add_node("research", research_graph). The subgraph receives the parent's state, and its updates to shared keys flow back. Keys only the subgraph knows stay private to it.

Call it from a node function when the schemas differ. The wrapper node translates: build the subgraph's input from the parent state, invoke it, and map the result back into a parent update. This keeps each team's state design independent.

Other details:

  • Persistence: compile only the parent with a checkpointer; subgraphs inherit it automatically. Pass checkpointer=True to a subgraph's compile if it should keep its own memory across calls (for example a sub-agent that remembers its conversation).
  • Streaming: pass subgraphs=True to stream to receive events from inside subgraphs too; each event's namespace tells you which subgraph emitted it.
  • Interrupts inside a subgraph pause the whole run and resume correctly.
  • Inspection: graph.get_state(config, subgraphs=True) includes subgraph state.
  • Leaving a subgraph: a node inside it can return Command(graph=Command.PARENT, goto="other_node") to jump to a node in the parent graph, the basis of agent handoffs. Declare the possible targets with destinations= when adding the subgraph node.

Example

from typing import TypedDict
from langgraph.graph import StateGraph, START, END


class ResearchState(TypedDict):        # child schema
    query: str
    findings: list[str]


def search(state: ResearchState) -> dict:
    return {"findings": [f"result for {state['query']}"]}


rb = StateGraph(ResearchState)
rb.add_node(search)
rb.add_edge(START, "search")
research_graph = rb.compile()


class ReportState(TypedDict):          # parent schema (different keys)
    topic: str
    report: str


def do_research(state: ReportState) -> dict:      # wrapper translates state
    out = research_graph.invoke({"query": state["topic"], "findings": []})
    return {"report": "; ".join(out["findings"])}


pb = StateGraph(ReportState)
pb.add_node(do_research)
pb.add_edge(START, "do_research")
pb.add_edge("do_research", END)
print(pb.compile().invoke({"topic": "solar", "report": ""}))
# {'topic': 'solar', 'report': 'result for solar'}

Remember

  • Shared keys: add the compiled subgraph directly as a node
  • Different schemas: invoke it inside a wrapper node and translate
  • Only the parent needs a checkpointer; stream with subgraphs=True
  • Command(graph=Command.PARENT, goto=...) jumps out to the parent

Check yourself

  1. Parent and subgraph share no state keys. How do you connect them?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: docs.langchain.com/oss/python/langgraph/use-subgraphs