What I learned about LangGraph
🧠 My Journey Into State Machines for LLMs
Recently, I decided to dive into AI and LLMs. I had already built a few simple MCP servers using TypeScript,
Then I decided to dive LangChain and RAG system. I watched a few tutorials — most of them were Python-based and, unfortunately, a bit outdated.
When I tried to follow along, I noticed that some classes used in those videos were already deprecated. That’s when I stumbled upon LangGraph, which looked like an extension or evolution of LangChain.
At first, I was confused. I don’t have a formal background in AI — I didn’t study it in university. So I started self-learning and asking questions directly to an LLM (shoutout ChatGPT).
🤔 My First Impressions of LangGraph
Initially, I thought LangGraph was just a tool to give memory to an LLM. While working with LangChain, I noticed that many of the memory-related classes were replaced or deprecated in favor of LangGraph persistence — so I followed the examples blindly and ended up building a simple LangGraph-powered console chat app in TypeScript using Bun.
But every time I wanted to improve the app, I kept getting redirected back to LangGraph concepts. That’s when I realized: I need to actually understand what this thing is .
💡 What LangGraph Really Is (At Least To Me)
At its core, LangGraph is like a state management system — but designed to handle the complexity of LLM apps. You define:
- Nodes (each does some processing)
- Edges (control the flow)
- And a shared state (accessible to all nodes) It reminds me a lot of XState, or even n8n, where you define visual workflows as a set of steps connected by logic.
🏭 A Mental Model That Helped Me
Imagine a whiteboard in a factory. The factory has several chains (pipelines). Each station reads from the whiteboard, processes something, and writes its result back. The whiteboard holds the shared state.
- Each operator is like a node’s callback function.
- Each station is a node.
- The whiteboard is the LangGraph state object.
- The workflow on the whiteboard (arrows, instructions) is the graph edges. Operators don’t talk directly to each other. They just read and write to shared memory — and follow the flowchart.
🧱 Everything Is a Runnable
One important thing I realized while learning LangChain and LangGraph is this:
Almost everything is a Runnable.
LLM wrappers, tools, chains, retrievers — they all inherit from a common Runnable class and expose a common interface:
.invoke(input) → output.
This makes the whole system feel super modular and composable. You can plug things together just like Lego blocks — because they all follow the same shape.
So when we’re defining a LangGraph workflow, we’re not doing anything magical.
We’re just defining a set of nodes, and each node is usually just a Runnable.
graph.addNode("summarizer", summarizerRunnable);
graph.addNode("qaTool", questionAnsweringRunnable);
Each of those nodes can invoke() on a piece of input — usually some shared state.
That’s it!
🧠 LangGraph for Frontend Devs: Think of It Like Redux or Zustand
If you come from frontend dev (React/TS/etc), it might help to think of LangGraph like this:
- The
statein LangGraph is like your global app state. - Each
node(Runnable) is like areducer,selectoror even amutator function. - The
edgesbetween the nodes represent theexplicit control flow, just likeXstatetransition or middleware chaining. - Calling
graph.compile()is like wiring up your state logic.
So in short:
LangGraph is a state manager with built-in control flow — like a programmable XState with LLM support.
LangGraph gives you a way to:
- Manage shared memory/state
- Pass that state between logic units (nodes)
- Control the flow of execution (like a state machine)
So unlike Redux where reducers just fire based on actions, in LangGraph, you manually define the control flow — like:
START → nodeA → nodeB → nodeC → END
That’s the special twist: it’s a state manager with a built-in flow engine.
📦 Bonus: Runnables Are Both Mutators and Consumers
Runnables can:
- Consume part of the state (like a selector)
- Mutate or extend it (like a reducer)
const summarizer = Runnable.from(async (state) => {
const summary = await someLLM.predict(state.inputText);
return { ...state, summary };
});
So if you’re used to manipulating state in frontend apps — LangGraph won’t feel that foreign.
Now Let’s Look at a Simple Graph
const graph = new StateGraph(MessagesAnnotation);
Define nodes:
graph
.addNode("firstNode", firstNodeRunnable)
.addNode("secondNode", secondNodeRunnable)
.addNode("thirdNode", thirdNodeRunnable);
This just drops 3 independent nodes into the space:
Now connect the dots (add edges):
graph
.addEdge(START, "firstNode"); // start -> firstNode
.addEdge("firstNode", "secondNode")// firstNode -> secondNode
.addEdge("secondNode", "thirdNode")// seconNode -> thirdNode
.addEdge("thirdNode", END); // thirdNode -> END
Resulting in this flow:
START → [firstNode] → [secondNode] → [thirdNode] → END
Now compile the graph:
const app = graph.compile();