LangGraph Cheatsheet: StateGraph, Nodes and Checkpoints
By DevShelfHub
LangGraph is LangChain's stateful-graph orchestration layer for building production-grade AI agents: you define a StateGraph of nodes (Python functions), connect them with typed edges and conditional routing, and attach a checkpointer for persistence and human-in-the-loop interrupts. This cheatsheet covers StateGraph setup, nodes, edges, reducers, checkpointers, streaming, interrupt/resume, subgraphs, and common multi-agent patterns.
110 items
◷ 8 min
Graphs
State
Checkpoints
LangGraph is the stateful graph orchestration layer built on top of LangChain, designed for production-grade AI agents that need more than a single chain. Where LangChain's LCEL handles linear pipelines, LangGraph lets you define a StateGraph — a directed graph of nodes (plain Python functions) connected by typed edges. The shared state object flows through nodes, each of which reads and writes to it; reducers control how values accumulate (e.g., appending messages vs. overwriting a counter). Conditional edges let you route between nodes based on state, enabling ReAct loops, retry cycles, and branching workflows.
The killer feature is the checkpointer: every step is persisted to a backend (memory for development, SQLite or Postgres for production), giving you pause-and-resume, time-travel debugging, and human-in-the-loop interrupts. An interrupt pauses the graph before or after a node and waits for external input before the run resumes — essential for approval workflows, data-entry corrections, or any scenario where an agent must wait for a human decision. Subgraphs let you compose multiple StateGraphs into larger systems with isolated state namespaces.
LangGraph ships with a LangGraph Platform (managed hosting with built-in queuing, resumption, and streaming), but the open-source library is fully self-hostable. All graph runs support streaming at the node level and at the LLM token level simultaneously, so the frontend can show progress as the agent reasons. This cheatsheet covers the daily LangGraph surface: StateGraph construction, nodes, edges, reducers, checkpointers, streaming modes, interrupt/resume, subgraph composition, and the prebuilt ReAct agent pattern.
LangGraph sits under LangChain — messages, models, tools come from
langchain-core. The graph and
checkpointer primitives are new. Checkpointers ship in separate packages now
(langgraph-checkpoint-sqlite,
-postgres) — the in-memory one stays in the core package.
LangGraph Platform is the hosted runtime, but everything in this sheet runs locally.
Hand-rolled LangGraph agent with a tool, SQLite checkpointer, streaming, and a thread id.
Replace search with your real tool and you have a working stateful bot.
python
from typing import Annotated, TypedDict
from langgraph.graph import StateGraph, START, END
from langgraph.graph.message import add_messages
from langgraph.prebuilt import ToolNode
from langgraph.checkpoint.sqlite import SqliteSaver
from langchain_core.messages import HumanMessage
from langchain_core.tools import tool
from langchain_openai import ChatOpenAI
class State(TypedDict):
messages: Annotated[list, add_messages]
@tool
def search(q: str) -> str:
"""Stub web search."""
return f"top result for '{q}': LangGraph is a state-machine library."
llm = ChatOpenAI(model="gpt-4o-mini").bind_tools([search])
def agent(state: State) -> dict:
return {"messages": [llm.invoke(state["messages"])]}
def needs_tool(state: State) -> str:
return "tools" if state["messages"][-1].tool_calls else END
g = StateGraph(State)
g.add_node("agent", agent)
g.add_node("tools", ToolNode([search]))
g.add_edge(START, "agent")
g.add_conditional_edges("agent", needs_tool, ["tools", END])
g.add_edge("tools", "agent")
with SqliteSaver.from_conn_string("checkpoints.db") as saver:
app = g.compile(checkpointer=saver)
cfg = {"configurable": {"thread_id": "user_42"}}
for chunk in app.stream(
{"messages": [HumanMessage("What is LangGraph?")]}, cfg,
):
print(chunk)
Best practiceGood to know
Reducers replace by default. A node returning {"items":[x]} overwrites the list.
Use Annotated[list, operator.add] or add_messages when you want append semantics.
Prefer dynamic interrupt() over static interrupt_before.
Dynamic pauses can carry payload to the human and survive across distributed workers; static pauses are a coarser tool.
Command(update=…, goto=…) is faster than routing.
When a node already knows where it wants to go, return a Command and skip the conditional-edge round trip.
Common trapsWatch out for
Missing thread_id with a checkpointer = silent statelessness.
The graph runs but starts from a fresh thread every call. Always set configurable.thread_id.
Recursion limit hits on routing loops.
Default is 25 supersteps. An agent that keeps calling tools without progress will hit it. Tune recursion_limit or add a termination signal in your router.
SqliteSaver is a context manager, not a value.
Use with SqliteSaver.from_conn_string(…) as saver:. Storing the returned object outside the block leaves a closed connection.
LangGraph is a graph-based agent orchestration library built on LangChain. It models workflows as directed graphs where nodes are Python functions or LLM calls, edges control routing, and a shared TypedDict state is passed between nodes. Unlike linear chains, LangGraph supports cycles, branching, and long-running agents with memory via checkpointers.
What is a StateGraph in LangGraph?
StateGraph is the core graph class. You define a TypedDict schema for shared state, add nodes (functions that read and write state), connect them with edges or conditional edges, then compile the graph with graph.compile(). The compiled graph is a Runnable that accepts an initial state dict and streams or returns the final state after execution.
How do checkpoints work in LangGraph?
A checkpointer (MemorySaver, SqliteSaver, PostgresSaver) serialises the full graph state after every node execution. Pass it to graph.compile(checkpointer=...) and supply a thread_id in the config to resume a specific conversation. Checkpoints enable long-running agents, time-travel debugging, and fault recovery without re-running completed steps.
What is human-in-the-loop in LangGraph?
Human-in-the-loop pauses graph execution at a designated node so a human can review, approve, or correct the agent output before it continues. Set interrupt_before=[node_name] in compile() to pause before a node, then resume with graph.invoke(None, config=thread_config) after the human has taken action. The agent resumes from the checkpoint without replaying prior steps.
What is the difference between LangChain and LangGraph?
LangChain provides model wrappers, prompt templates, retrievers, and simple sequential chains. LangGraph adds a stateful graph execution engine for cyclic, branching, and multi-agent workflows with explicit state schemas and checkpointing. Most new complex agent work starts with LangGraph rather than the legacy LangChain AgentExecutor class.