tl;dr. langchain gives you the parts — models, tools, messages, structured output. langgraph gives you the composition: a state machine where nodes are functions, edges are control flow, and the state is a typed object every node reads and updates. the day your agent system needs a loop, a branch, or a pause, you have a graph problem whether you use a graph library or not.
chains run forward
langchain's original abstraction is the chain: prompt in, model, parser, answer out. it's a pipe, and pipes are great at what pipes do — one direction, no decisions.
// a chain: data flows one way, no decisions, no loops.
const answer = await prompt
.pipe(model)
.pipe(parser)
.invoke({ question });
// fine — until the output needs to be checked, retried,
// routed to a specialist, or approved by a human.
every real agent system i've built stopped being a pipe within a week.
the output needs validation, and validation failure means a retry —
that's a loop. different inputs need different specialists — that's a
branch. a risky action needs sign-off — that's a pause, which is the
control-flow feature nobody's pipe has. you can fake all three with
while loops and if statements around chain
calls, and that's exactly what people do, and that code is where agent
systems go to become unmaintainable.
an agent system is a state machine
the reframe that makes langgraph click: stop thinking "conversation" and start thinking "state machine." there is a bag of state — messages so far, the working draft, which reviews passed. there are functions that each do one thing to that state. and there are rules for which function runs next, some fixed, some decided by looking at the state. that's the whole model.
// the same system as a graph: nodes + edges + state.
//
// ┌──────────┐
// START ─► │ triage │
// └────┬─────┘
// route(state) — a decision, not a pipe
// ┌───────┴────────┐
// ▼ ▼
// ┌─────────┐ ┌─────────┐
// │ billing │ │ tech │
// └────┬────┘ └────┬────┘
// └───────┬────────┘
// ▼
// ┌─────────┐
// │ review │ ──► needs another pass? back to triage.
// └────┬────┘
// ▼
// END - state
one typed object, shared by every node. the single source of truth
for the run. in the next lesson this becomes an
Annotationwith reducers. - nodes plain async functions: state in, partial state out. a node can call a model, call a tool, call nothing. the graph doesn't care.
- edges control flow. fixed edges ("after triage, always run billing") and conditional edges ("look at the state, decide where to go") — the second kind is where agent behaviour actually lives.
what the runtime buys you
modelling control flow as data instead of code is a real cost — it's
more ceremony than a while loop. what you get back is
everything that's painful to hand-roll:
- persistence. a checkpointer snapshots state at every step. a run can crash, pause for a day, or wait for a human — and resume exactly where it stopped. this is lesson seven, and it's the feature that justifies the framework.
- streaming. state updates stream out as nodes complete, so a ui can show "reviewer is running" instead of a spinner over a five-minute void.
- visibility. the graph is inspectable data. you can render it, trace a run through it, and point at the node where things went wrong — instead of reconstructing control flow from log lines.
createAgent helper is a langgraph graph under the hood, and
it retired the older createReactAgent prebuilt you'll still
meet in tutorials. so this isn't an either/or: you'll use langchain's
models, messages, and tool() helper inside langgraph's
structure the whole course. parts from one, composition from the other.
when you don't need this
honesty section. one agent, one toolset, one sitting, a human watching — that's a react loop, and the one-call version or a harness like the claude agent sdk is the right amount of machinery. reach for the graph when the system needs structure between agents: gates, teams, fan-out, resumable runs. the rule i use: the moment i draw boxes and arrows on paper to explain the system, the system is a graph, and pretending otherwise just means i maintain the graph in prose.
when it breaks
- graphs for pipes. a three-step always-forward workflow gains nothing from langgraph except dependencies. if there are no branches, loops, or pauses, write three awaits.
- the framework as the design. langgraph makes composition cheap, which makes over-composition cheap. eleven agents where two would do is still a design smell — the patterns tell you what to build; the graph only tells you how to wire it.
next: state, nodes, edges — the actual api, and the reducer detail that causes most first-week bugs.