КОД</>БЕЗ МЕЖ
← All articles

LangGraph vs LangChain: when to use which

"LangGraph vs LangChain" is the question almost everyone trips over when they first walk into agent territory. No surprise: the names rhyme, the team is the same, the docs are intertwined. But these are not competitors and not two versions of one thing. LangChain is the broad toolkit. LangGraph is the narrow state-orchestration layer that sits on top of it. Let me draw the line honestly, with no marketing, and tell you what to reach for and when.

The short answer in two sentences

LangChain is a set of building blocks: model wrappers, document loaders, retrievers, parsers, integrations, and chains. It answers "how do I assemble an LLM app from standard parts". LangGraph is a separate library from the same team that answers "how do I orchestrate an agent that has loops, state, and pauses". The first is about the parts; the second is about coordinating complex behavior.

If you have already read when LangGraph beats the vanilla SDK → — that one covered what a StateGraph is and when the graph beats raw SDK code. I will not repeat it here: the focus is squarely on the LangChain vs LangGraph pair and exactly where the line between them falls.

What LangChain actually is

LangChain showed up as the answer to an early-2023 pain: everyone was hand-writing the same thing — prompt templates, a model call, response parsing, pulling context out of documents. LangChain gathered those patterns into one ecosystem. Today it is, first and foremost:

The key point: LangChain is excellent for linear, lightly branched scenarios. A chain is a pipe — data goes in one end and comes out the other. As long as the logic flows one way, LangChain saves you weeks.

Where LangChain starts to crack

The problems surface the moment an agent needs to loop back. A classic chain cannot elegantly do "try → check → redo". In the original LangChain that job fell to AgentExecutor — a black box that spun its own reasoning loop inside. On simple cases it worked, but the moment you needed to step into the transition logic, add a human pause, or persist state, the hacks began.

That is exactly why the LangChain team shipped LangGraph as a separate thing. It was an honest admission: the chain model does not carry complex agent behavior. They needed an explicit graph where transitions are visible and state is controlled. So the clean split appeared: LangChain stayed the toolkit of parts, LangGraph became the orchestration layer.

What LangGraph is and how it differs

LangGraph describes an agent as a state graph: nodes do the work, edges decide where to go next, and state flows between them. Unlike a chain, the graph can do three things a pipe cannot:

The most important thing — and the one that surprises people: LangGraph does not require LangChain. Inside a node you can call the vanilla OpenAI or Anthropic SDK and never touch a chain. The reverse works too: you can use LangChain integrations (loaders, retrievers) inside LangGraph nodes. They compose, but they are not hard-wired to each other.

The difference in code: chain vs StateGraph

The shortest way to feel the difference is to see the same task in two styles. First a simple LangChain chain: prompt → model → parser. A one-way pipe.

from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser

prompt = ChatPromptTemplate.from_template(
    "Explain briefly: {question}"
)
model = ChatOpenAI(model="gpt-4o-mini")

# LCEL: steps compose with the | operator
chain = prompt | model | StrOutputParser()

answer = chain.invoke({"question": "What is LangGraph?"})

Clean, readable, zero overhead. But there is no loop, branch, or pause here — data just passes straight through. Now the same task, but with a "if the answer is weak, try again" condition, on LangGraph:

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

class State(TypedDict):
    question: str
    answer: str
    tries: int

def call_model(state: State) -> dict:
    reply = model.invoke(state["question"]).content
    return {"answer": reply, "tries": state["tries"] + 1}

def is_good(state: State) -> str:
    # conditional edge: loop back or exit
    if "i don't know" in state["answer"] and state["tries"] < 3:
        return "retry"
    return "done"

graph = StateGraph(State)
graph.add_node("call_model", call_model)
graph.add_edge(START, "call_model")
graph.add_conditional_edges(
    "call_model", is_good, {"retry": "call_model", "done": END}
)

app = graph.compile()
result = app.invoke({"question": "What is LangGraph?", "tries": 0})

See the difference? The chain is an expression that flows left to right. The graph is a state machine: retry points the node at itself, done goes to END. If your logic fits in one pass, the first version is shorter and more honest. If retries, branches, or pauses appear, the second one does not collapse into a wall of if statements.

LangChain vs LangGraph: the table

LangChain wins

  • RAG and document search
  • Linear pipelines (prompt → model → parser)
  • You need ready integrations and loaders
  • Structured output against a schema
  • Prototype where build speed matters

LangGraph wins

  • Loops, branches, retries
  • Human-in-the-loop with pauses
  • State persisted for days
  • Multi-agent work handoff
  • You need replay and transparent debug

Note: the rows in the two columns do not contradict each other. This is not "either-or", it is "whose tool goes where". RAG lives in LangChain. Orchestrating the agent that calls that RAG lives in LangGraph.

When to combine them

The most common real scenario is not a choice but a composition. LangGraph runs the process at the top level, and inside individual nodes you call LangChain bricks. A typical setup for a support agent with a knowledge base:

So the line is simple: LangChain is "what to build a node out of", LangGraph is "how to wire nodes into a stateful process". Once the task grows into several agents handing work to each other, this composition becomes mandatory — I broke that down in the multi-agent systems article →

Honestly: most simple apps do not need LangGraph

I will say it straight, because it saves clients money. If your product is a chat over documents, a bot that answers FAQs, or a template-driven text generator, LangChain is enough (and often the vanilla SDK is). The graph here is ceremony for the sake of ceremony: you pay in complexity for capabilities you never use.

LangGraph starts to pay off once at least one of three things appears in the process: a loop that goes back; a pause for a human decision; state that has to survive a restart. Until none of that exists, a chain is the more honest answer. A framework should show up because of pain, not "just in case".

Common selection mistakes

  1. Thinking LangGraph replaces LangChain. It does not. It sits on top of it (or beside it). You still pull integrations and retrievers from LangChain more often than not.
  2. Dragging LangGraph into a simple RAG. Document search is a linear flow. The graph adds nothing here but moving parts.
  3. Being afraid to use LangGraph without LangChain. You can write nodes on the vanilla SDK. If you do not want someone else's abstractions, skip them — the graph is fine without them.
  4. Staying on the old AgentExecutor for complex agents. If you have loops and branches bolted onto chains, that is the very pain the LangChain team itself walked away from into the graph. Do not repeat that path.

How to choose: the short test

Choose LangChain if you have RAG, a linear pipeline, or you need ready integrations and loaders, and the logic flows one way with no returns. In 70% of product cases that is plenty.

Choose LangGraph if loops, branches, human pauses, state persistence, or several agents handing off work have appeared. Then the graph pays for itself on the very first serious debug.

Combine both if the agent runs a complex process (LangGraph) but leans on RAG and integrations inside its nodes (LangChain). This is the most typical production setup.

That exact architecture — a graph for orchestration plus the right bricks inside the nodes — is what I design and build as part of multi-agent system development → from stack choice to deploy and monitoring.

If you are not sure which side of the line your case is on, message me. 30 minutes on a call and I will tell you honestly whether you need a graph at all or a chain is enough.

Message @tribeofdanel →