What is StateGraph?
StateGraph is the central orchestration primitive in LangGraph. A StateGraph is constructed with a TypedDict subclass that defines the shape of the shared state—every node in the graph reads from and writes to this state dict. Nodes are Python callables that receive the current state and return a dict of updates. LangGraph merges the returned dict using reducer annotations on the TypedDict: fields annotated with Annotated[list, add_messages] accumulate values, while plain fields are overwritten.
Edges define transitions. A direct edge (add_edge) always transitions from one node to another. A conditional edge (add_conditional_edges) calls a function on the state to decide which node to route to next, and can also route to the END sentinel to terminate the graph. After adding nodes and edges, call graph.compile() to get an executable CompiledGraph—the compile step validates graph structure and wires up the checkpointing system.
Compiled graphs support .invoke() for synchronous execution, .ainvoke() for async, and .stream() for streaming token output. For persistent multi-turn conversations, pass a MemorySaver checkpointer to compile(): graph.compile(checkpointer=MemorySaver()). The checkpointer snapshots state after each node, allowing resumption from a given thread_id for human-in-the-loop interrupts and long-running agent sessions.
When to Use
You're building multi-step workflows, agents with loops, or conversational systems. Use StateGraph for anything more complex than linear chains.
Use Cases
- • Multi-step agent loops
- • Conversational AI
- • Decision trees
- • Complex workflows
- • State management
- • Looping patterns
Key Features
- ✓ Stateful execution
- ✓ Node composition
- ✓ Conditional routing
- ✓ Checkpointing
- ✓ Human-in-the-loop
- ✓ State history
When NOT to Use
For simple linear chains—use LCEL pipes instead.
Notes
compile() is required before invoke()
StateGraph itself is not invokable—only the compiled graph is. Always call compiled = graph.compile() before calling compiled.invoke(). Forgetting compile() raises AttributeError: StateGraph object has no attribute invoke.
add_messages reducer appends rather than replaces
Annotate your messages field as Annotated[list, add_messages] from langgraph.graph.message to append new messages to the list. Without the reducer, returning {"messages": [new_msg]} replaces the entire messages list—the most common bug in new LangGraph code.
Conditional edges must cover all possible outputs
If your routing function can return "search", "answer", or END, all three must appear in the path_map of add_conditional_edges. A missing route causes a KeyError at runtime when the unmapped value is returned.
MemorySaver is in-process only
MemorySaver stores checkpoints in RAM. For multi-process deployments (gunicorn, serverless), use SqliteSaver or PostgresSaver from langgraph.checkpoint. In-process state is lost when the process restarts.
thread_id scopes state isolation
Pass config={"configurable": {"thread_id": "user-123"}} to invoke() to scope the checkpoint to a specific user or session. Without thread_id, all invocations share the same checkpoint slot and will overwrite each other's state.
Import
from langgraph.graph import StateGraph
Key Parameters
| Parameter | Type | Default | Purpose |
|---|---|---|---|
| state_schema | Type | None | TypedDict defining state shape |
Code Examples
Create Graph
from langgraph.graph import StateGraph
from typing import TypedDict
class AgentState(TypedDict):
messages: list
graph = StateGraph(AgentState)
Conditional Routing
from langgraph.graph import StateGraph, END
from typing import Literal
def route(state) -> Literal["search", "answer"]:
if state["needs_search"]:
return "search"
return "answer"
graph.add_conditional_edges("agent", route, ["search", "answer"])
graph.add_edge("search", "agent")
graph.add_edge("answer", END)
Persistent Memory with MemorySaver
from langgraph.checkpoint.memory import MemorySaver
memory = MemorySaver()
compiled = graph.compile(checkpointer=memory)
# Scope state to a user session
config = {"configurable": {"thread_id": "user-123"}}
compiled.invoke({"messages": [HumanMessage("Hi")]}, config)
Common Mistakes
❌ Not defining a proper state schema
✅ Use TypedDict to define your state shape clearly
Related LangChain References
Browse the full LangChain API reference index to explore more classes, methods, and decorators, or start with the LangChain introduction tutorial for end-to-end context on building with StateGraph and the wider framework.
StateGraph FAQ
What is StateGraph in LangChain?
Build stateful agent workflows with LangGraph. StateGraph is the central orchestration primitive in LangGraph. A StateGraph is constructed with a TypedDict subclass that defines the shape of the shared state—every node in the graph reads from and writes to this state dict. Nodes are Python callables that receive the current state and return a dict of updates. LangGraph merges the returned dict using reducer annotations on the TypedDict: fields annotated with Annotated[list, add_messages] accumulate values, while plain fie…
Which package provides StateGraph?
DevShelfHub documents StateGraph from the langgraph package. Pin your installed LangChain version and match imports to the snippet on this page.
When should I use StateGraph?
You're building multi-step workflows, agents with loops, or conversational systems. Use StateGraph for anything more complex than linear chains.
When should I avoid using StateGraph?
For simple linear chains—use LCEL pipes instead.
How do I import StateGraph in Python?
from langgraph.graph import StateGraph
Where can I explore more LangChain API reference pages?
Open the LangChain API reference index on DevShelfHub to browse classes, methods, and decorators, each with runnable examples, parameters, common mistakes, and cross-links.