LangChain & LangGraph Best Practices
Ten practices for structuring graphs, state, and checkpoints so LangGraph agents stay debuggable, resumable, and safe under real traffic.
Search across all documentation pages
Ten practices for structuring graphs, state, and checkpoints so LangGraph agents stay debuggable, resumable, and safe under real traffic.
Use this checklist when you leave the tutorial graph and before you expose tools with side effects.
TypedDict/Pydantic; attach add_messages or other reducers only where merge semantics are required; keep secrets out of checkpointed fields.InMemorySaver only for local demos.interrupt(). Side effects after resume; idempotent code before interrupt; never bare-except around interrupt control flow.version="v2" stream parts for UIs; test consumers against multi-mode and subgraph ns fields.RetryPolicy on tool/model nodes; route permanent failures to error handlers or escalate branches.| Stage | Habits | Exit criterion |
|---|---|---|
| Design | 1-3 | Named nodes, typed state, allowlisted routes |
| Harden | 4-6 | Durable threads, HITL on danger, hard stops |
| Operate | 7-9 | Stable streams, traces, smart retries |
| Evolve | 10 | Pins, migrations, and docs owned |
InMemorySaver.interrupt_before debug flags.Exception around interrupt().from typing import Annotated, Literal, TypedDict
from langgraph.graph import StateGraph, START, END
from langgraph.graph.message import add_messages
from langgraph.checkpoint.memory import InMemorySaver # swap for durable saver
class State(TypedDict):
messages: Annotated[list, add_messages]
steps: int
def agent(state: State) -> dict: ...
def tools(state: State) -> dict: ...
def route(state: State) -> Literal["tools", "__end__"]:
if state.get("steps", 0) >= 8:
return "__end__"
last = state["messages"][-1]
return "tools" if getattr(last, "tool_calls", None) else "__end__"
g = (
StateGraph(State)
.add_node("agent", agent)
.add_node("tools", tools)
.add_edge(START, "agent")
.add_conditional_edges("agent", route, {"tools": "tools", "__end__": END})
.add_edge("tools", "agent")
.compile(checkpointer=InMemorySaver())
)Durable checkpoints with thread ids (4), stop conditions (6), and tracing (8). Without those, branching polish will not save incidents.
No. Use interrupts for irreversible or high-risk actions. Low-risk reads can run automatically with strong logging.
Whenever product policy changes, and after any incident where the wrong branch ran. Treat maps as reviewed config.
No. Graphs structure execution; evals prove task success across paths and prompt/model changes.
Fixed single-path jobs with no resume needs may be simpler as scripts or plain chains. See framework comparison guidance.
LangChain: models, tools, parsers. LangGraph: durable multi-step orchestration. Keep the boundary clean in imports and mental models.
Branch mix, interrupt wait times, tool error rate, checkpoint storage growth, cost per successful thread, and timeout/retry counts.
Add fields as optional, deploy readers first, backfill or default on read, and avoid renaming hot keys without a migration plan.
Related: The LangGraph Mental Model
Related: LangChain & LangGraph Basics
Related: Building Your First Stateful Agent Graph
Related: Persistence and Checkpoints
Related: Human-in-the-Loop Approval Nodes
Related: Observability with LangSmith
Stack versions: Pins from the category manifest (verify at build): OpenRouter (~315+ models, July 2026 pricing/fees); LangGraph 1.0+; CrewAI 1.14+; Microsoft Agent Framework 1.0; Vercel AI SDK 6; Pydantic AI (latest); LlamaIndex (latest); OpenAI Agents SDK (latest + MCP); MCP (Linux Foundation governance); A2A (HTTP+SSE+JSON-RPC 2.0); Solana
@solana/web3.js+@solana/spl-token.
Reviewed by Chris St. John·Last updated Jul 16, 2026