In plain English
LangChain and LangGraph come from the same company (LangChain Inc.) and share the same package ecosystem. But they solve different problems. LangChain is a collection of composable building blocks — model clients, prompt templates, document loaders, retrievers, and the pipe (|) operator that connects them. LangGraph is a lower-level orchestration engine that models your workflow as an explicit state machine: nodes, edges, and a shared state object that every node reads and updates.
A good analogy: building with LangChain is like snapping Lego bricks together in a line. Each brick clicks onto the next, output flows forward, and you end up with a clean linear shape. LangGraph is more like wiring a circuit board — you still use the same components, but now current can loop back, fork into branches, and visit the same node twice before the circuit completes.
As of October 2025, both frameworks reached v1.0 (general availability). One key change: LangChain's high-level agent helpers now run on a LangGraph runtime internally. The two tools are not alternatives — they are layers. LangChain gives you speed; LangGraph gives you control. Most non-trivial production agents use both.
Why it matters
The confusion between these two tools is one of the most common stumbling blocks for developers entering the LLM ecosystem. Many tutorials teach LangChain chains first, then silently switch to LangGraph for "agents" — without explaining why the switch happened or what problem it solved. That leads to two failure modes: developers who use LangGraph for everything (overkill for a simple RAG pipeline) and developers who try to squeeze complex agent loops into a chain (fragile, hard to debug).
Getting the boundary right saves you real time. A RAG pipeline built with plain LCEL chains is around 30 lines of code and trivially readable. The same pipeline rebuilt as a LangGraph StateGraph is perhaps 80 lines — perfectly maintainable, but the extra complexity buys you nothing if you never need loops or checkpoints. Conversely, a multi-step research agent that needs to retry a web search, escalate to a human reviewer, and resume after a server restart requires LangGraph — trying to simulate that in a linear chain produces spaghetti code.
The production case for LangGraph
Before LangGraph, production teams at companies like Uber, LinkedIn, and Klarna were building fragile stateful agents by layering custom retry logic on top of LangChain chains. LangGraph formalized what they were already doing: explicit state, conditional routing, and persistence. By the time it hit v1.0 it was already battle-tested at scale, which is why the LangChain team folded the agent runtime into LangGraph rather than the other way around.
How each tool works
LangChain: the pipe operator and Runnables
LangChain's modern core is the LangChain Expression Language (LCEL). Every component — a prompt template, a model call, an output parser — implements a Runnable interface with a uniform .invoke() / .stream() / .batch() API. You compose Runnables with the | pipe operator, and data flows left to right. The chain is a directed acyclic graph (DAG): there are no cycles, no shared mutable state, and no branching based on intermediate outputs.
from langchain_anthropic import ChatAnthropic
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
prompt = ChatPromptTemplate.from_template(
"Answer using this context:\n{context}\n\nQuestion: {question}"
)
model = ChatAnthropic(model="claude-opus-4-5")
parser = StrOutputParser()
# The chain: prompt → model → parser (left to right, no loops)
chain = prompt | model | parser
result = chain.invoke({"context": docs, "question": "What is LCEL?"})Parallel execution, streaming, retries, and fallbacks are all built into the Runnable interface — you opt in per-component. But the topology is fixed at definition time. You cannot route to a different node based on what the model said.
LangGraph: state, nodes, and edges
LangGraph centers on three primitives. The state is a TypedDict that acts as a shared scratchpad every node can read and partially overwrite. Nodes are ordinary Python functions that receive the current state and return a dict of fields to update. Edges are either unconditional (add_edge("a", "b")) or conditional (add_conditional_edges) — the conditional kind runs a routing function that inspects the state and picks the next node dynamically, which is what enables loops and branching.
from typing import TypedDict, Literal
from langgraph.graph import StateGraph, START, END
class AgentState(TypedDict):
messages: list
attempts: int
def call_llm(state: AgentState) -> dict:
reply = llm.invoke(state["messages"])
return {"messages": state["messages"] + [reply],
"attempts": state["attempts"] + 1}
def route(state: AgentState) -> Literal["call_tool", "__end__"]:
last = state["messages"][-1]
return "call_tool" if last.tool_calls else END
def call_tool(state: AgentState) -> dict:
# execute tool calls, append results
...
graph = StateGraph(AgentState)
graph.add_node("llm", call_llm)
graph.add_node("call_tool", call_tool)
graph.add_edge(START, "llm")
graph.add_conditional_edges("llm", route)
graph.add_edge("call_tool", "llm") # loop back
app = graph.compile()Notice the last add_edge call routes call_tool back to llm. That is a cycle — impossible in a pure LCEL chain, but the fundamental pattern for any agent that uses a tool and then reasons about the result.
- Directed acyclic graph (DAG)
- Pipe operator: A | B | C
- Output of each step feeds the next
- No shared mutable state
- Topology fixed at definition time
- Best for: RAG, prompt pipelines, simple chatbots
- Cyclic state machine
- Nodes + conditional edges
- All nodes share typed State object
- Explicit state persisted by checkpointer
- Routing decided at runtime by router function
- Best for: agents with loops, retries, human review
Checkpointers: how LangGraph persists state
One of LangGraph's most important features is its checkpointer system. After every node execution, LangGraph can serialize the full state and write it to a store (in-memory, SQLite, Postgres, or Redis). This means an agent can be interrupted — by a server restart, a rate limit, or a human review step — and resume exactly where it left off. No custom database logic required. LangChain chains have no equivalent built-in; state is ephemeral and lives only in the function call stack.
Choosing between them: a decision guide
Here is the clearest way to decide which tool to reach for. Ask yourself these four questions about your workflow, in order:
- Does it loop? If the agent ever needs to call a tool, inspect the result, and decide whether to call again — that is a cycle. Use LangGraph.
- Does it branch on intermediate output? If you route to different nodes depending on what the LLM said (e.g., search vs. calculate vs. answer), use LangGraph.
- Does it need to pause and resume? Human-in-the-loop review, long-running background jobs, multi-day workflows — all require LangGraph checkpointers.
- Does it run across multiple specialized agents? Multi-agent handoffs where a supervisor routes tasks to sub-agents are a LangGraph pattern built around the
splittopology.
If you answered no to all four, a LangChain LCEL chain is the right choice. It is simpler to read, simpler to test, and simpler to debug. Reach for LangGraph only when the workflow has genuinely earned it.
| Use case | Best tool | Why |
|---|---|---|
| RAG pipeline (retrieve → prompt → answer) | LangChain (LCEL) | Linear DAG, no loops needed |
| Simple chatbot with memory | LangChain (LCEL) | Memory can be injected as context; no graph required |
| Document summarization pipeline | LangChain (LCEL) | Map-reduce pattern fits the pipe operator |
| ReAct agent (reason → act → observe loop) | LangGraph | Requires a cycle back from observe to reason |
| Agent with human review before taking action | LangGraph | Checkpointer + interrupt lets the graph pause |
| Multi-agent system with specialist sub-agents | LangGraph | Supervisor → specialist routing is a graph pattern |
| Long-running background research job | LangGraph | Needs durable state across server restarts |
| Prototype / quick experiment | LangChain (LCEL) | Faster to write; drop to LangGraph later if needed |
Using LangChain and LangGraph together
The most practical pattern is to use LangChain components inside LangGraph nodes. LangGraph provides the control-flow skeleton (state, routing, persistence) while LangChain provides the pre-built integrations (model clients, retrievers, output parsers, tool wrappers). You are not picking one or the other — you are using LangChain's breadth at the leaf level and LangGraph's structure at the orchestration level.
from langchain_anthropic import ChatAnthropic
from langchain_core.prompts import ChatPromptTemplate
from langgraph.graph import StateGraph, MessagesState
from langgraph.checkpoint.memory import MemorySaver
# LangChain component: model + prompt
model = ChatAnthropic(model="claude-opus-4-5")
prompt = ChatPromptTemplate.from_messages([
("system", "You are a helpful assistant."),
("placeholder", "{messages}"),
])
chain = prompt | model # LCEL chain used as a sub-component
# LangGraph node that calls the LCEL chain
def agent_node(state: MessagesState) -> dict:
response = chain.invoke({"messages": state["messages"]})
return {"messages": [response]}
# LangGraph graph that gives the node durable state
graph = StateGraph(MessagesState)
graph.add_node("agent", agent_node)
graph.set_entry_point("agent")
graph.set_finish_point("agent")
# MemorySaver checkpoints state between turns
app = graph.compile(checkpointer=MemorySaver())This is the pattern the LangChain team recommends for production: LCEL chains handle prompt formatting and model calls inside each node, while LangGraph manages the routing, state, and persistence across the whole agent lifecycle.
Migrating an existing LangChain agent
If you have a legacy AgentExecutor-based agent from LangChain 0.x, the recommended migration path is to replace it with an explicit StateGraph. The migration is usually a single-commit change: your tools stay the same, your model stays the same — you just replace the AgentExecutor wrapper with a LangGraph graph definition. The payoff is deterministic routing, native persistence, and easy human-in-the-loop injection without patching the executor internals.
Going deeper
Once you are comfortable with the basics of LangGraph, there are several advanced capabilities worth exploring that have no LangChain-chain equivalent.
Subgraphs and multi-agent architectures
LangGraph supports subgraphs — a compiled StateGraph can itself be used as a node inside a larger graph. This is the foundation of multi-agent systems: a supervisor graph routes work to specialist sub-agents (each their own compiled graph), aggregates their outputs, and decides what to do next. The specialist sub-agents can share no code with the supervisor; they communicate only through the shared state schema.
Human-in-the-loop (HITL)
LangGraph's interrupt primitive lets you pause a graph at any node and hand control back to a human (or an approval system). The graph state is persisted by the checkpointer, so the agent can be resumed minutes or days later after the human has reviewed and optionally edited the state. This pattern is especially common in agentic systems that have side effects — sending emails, writing files, calling external APIs — where you want a human gate before irreversible actions.
Streaming and partial outputs
Both frameworks support streaming, but in different ways. LCEL chains stream token-by-token output from model calls transparently — call .stream() instead of .invoke(). LangGraph adds a second streaming mode: streaming graph events — you receive a notification as each node starts and finishes, including the full state snapshot at each step. This event-level stream is invaluable for building agent UIs that show "thinking" progress rather than a blank spinner.
LangSmith for observability
LangSmith is the observability and evaluation platform that completes the LangChain ecosystem. It traces every node execution in a LangGraph run — inputs, outputs, latency, token count, and the full state at each step. You can replay any run, add automated evaluators, and compare runs across experiments. For production LangGraph agents, LangSmith integration is essentially mandatory: the graph's explicit state makes traces far more readable than the opaque call stacks you get from a raw API client.
When to skip both
LangChain and LangGraph are not the only options. If you are working primarily with Anthropic models, the Claude Agent SDK (also known as the Anthropic Agents SDK) provides a first-party orchestration layer with built-in tool use and multi-agent support without the LangChain dependency. If you are building with Google's models, Google ADK takes a similar graph-based approach to LangGraph but is tightly integrated with Gemini. The right tool depends on which provider you are committed to and how much of the LangChain ecosystem (integrations, community templates, LangSmith) you intend to use.
FAQ
Can I use LangGraph without LangChain?
Yes. LangGraph is its own package (langgraph) and has no hard dependency on the high-level LangChain abstractions. You can write nodes that call the Anthropic or OpenAI SDK directly, without any LangChain model wrapper. Many teams use LangGraph as a standalone orchestration layer and pull in only the specific LangChain integrations they need (e.g., langchain-anthropic for the model client).
Is LangGraph harder to learn than LangChain?
LangGraph has a steeper initial learning curve because you have to think in terms of state machines — nodes, edges, state schema, and routing functions — rather than a simple pipe. Most developers find that after building one or two agents with LangGraph, the mental model clicks and the explicitness becomes an asset rather than overhead. The official LangGraph tutorials are well-structured and reach a working agent in under an hour.
Should I migrate my existing LangChain agent to LangGraph?
If your agent uses AgentExecutor (the pre-v1.0 pattern), migrating to LangGraph is strongly recommended: AgentExecutor is deprecated and receives only security fixes. If your agent uses the newer create_agent helper from LangChain 1.0, it already runs on a LangGraph runtime — you only need to drop to explicit StateGraph if you need custom routing, checkpointing, or human-in-the-loop interrupts.
Does LangGraph work with models other than OpenAI?
Yes — LangGraph is model-agnostic. It orchestrates whatever Python functions you put in its nodes. Nodes can call Anthropic, Google Gemini, Mistral, a local Ollama instance, or any other model. LangChain model wrappers (langchain-anthropic, langchain-google-genai, etc.) make it convenient to swap providers, but they are optional.
What is the difference between LangGraph checkpointers and LangChain memory?
LangChain's ConversationBufferMemory and similar classes store conversation history in-process and inject it into prompts. They do not persist across server restarts and cannot checkpoint arbitrary agent state. LangGraph checkpointers serialize the entire State object — not just messages — to an external store (SQLite, Postgres, Redis) after every node execution. The agent can resume exactly where it left off after a failure, a restart, or a multi-day pause.
How do LangChain and LangGraph relate to LangSmith?
LangSmith is a separate product (cloud SaaS, with a free tier) for tracing, evaluating, and monitoring LLM applications built with LangChain or LangGraph. It is not required to run either framework, but it integrates deeply: every LCEL chain and every LangGraph node execution is automatically traced when you set the LANGCHAIN_TRACING_V2=true environment variable. For production agents, LangSmith traces make debugging and evaluation dramatically easier.