LangChain, layer by layer: how the 2026 stack is built, from create_agent down to the LangGraph runtime
An architecture guide to the LangChain stack in 2026: LangChain 1.x and create_agent with middleware, the LangGraph graph and its Pregel runtime, checkpoints and memory, human approvals with interrupt(), Deep Agents, Agent Server deployment, and the places where it bites in production.
LangChain in 2026 is three open-source libraries on one runtime, with LangSmith around them. Even the agent you get from create_agent compiles into a LangGraph graph. LangChain is the most used agent framework in Stack Overflow’s 2026 survey at 30.2%, with LangGraph at 18.8%, and it ranks first in our production ranking of ten frameworks. This guide takes the stack apart layer by layer, from the agent API you call down to the runtime that executes it. Everything is checked against the documentation and code of the Python package langgraph 1.2.16 (October 16, 2026); the JavaScript @langchain/langgraph has its own numbering (1.5.2) and some different defaults.
TL;DR
- Four layers: LangGraph (runtime), LangChain 1.x (agent layer), Deep Agents (harness for long tasks) and LangSmith (tracing, evals, deployment). The three libraries are MIT; LangSmith is commercial.
create_agenttakes a model, tools, a prompt, middleware and a response format, and returns a compiled graph. Six middleware hooks wrap the loop.- A graph is state with reducers, nodes and edges. The runtime runs it in super-steps and saves a checkpoint at each step boundary.
interrupt()pauses a run for a person; on resume, the node restarts from the top.- Where it bites:
Commandplus a static edge runs both routes, running threads pick up new code, and checkpoints are an attack surface.
01 · The stack: three libraries, one runtime

Source: LangGraph overview and LangChain products docs, October 2026.
| Layer | What it does | License |
|---|---|---|
| LangGraph | The runtime: state, graphs, checkpoints, interrupts, streaming | MIT, langgraph 1.2.16 |
| LangChain 1.x | The agent layer: create_agent, middleware, models, tools, messages | MIT |
| Deep Agents | A harness for long tasks: planning, subagents, filesystem tools, context management | MIT |
| langchain-core | Shared interfaces for models, messages and tools | MIT |
| LangSmith | Tracing, evals, prompts and deployment for any framework | Commercial |
The docs put the relationship plainly: “LangChain 1.0 is built on top of LangGraph,” and “you don’t need to know LangGraph to use LangChain.” The reverse also holds: LangGraph “can be used without LangChain,” although the langgraph package itself depends on langchain-core.
Which layer do you need? A tool-calling agent with a prompt and maybe structured output: create_agent. Your own flow with branches, parallel steps and custom state: a StateGraph. Long open-ended tasks with plans, subagents and files: Deep Agents. Traces, evals and hosting, for any of these or for another framework: LangSmith.
02 · The agent layer: create_agent and middleware

Source: LangChain 1.0 release notes and middleware docs.
LangChain 1.0 replaced LangGraph’s old create_react_agent with create_agent(model, tools, system_prompt, middleware, response_format, context_schema). It builds the familiar loop (model, tools, model again) and returns a compiled LangGraph graph, so once you pass a checkpointer you get persistence, streaming, approvals and time travel without writing a graph.
The release notes call middleware “the defining feature of create_agent.” Six hooks let you step into the loop: before_agent and after_agent around the whole run, before_model and after_model around each model call, and wrap_model_call and wrap_tool_call that wrap the calls themselves. Middleware “is not a separate runtime”: the hooks run inside the compiled graph. Built-in middleware covers PII masking, summarization, human-in-the-loop approval, tool and model retries, model fallback and call limits. The human-in-the-loop middleware “requires a checkpointer.”
Three more changes in 1.0 matter day to day. Structured output “is now generated in the main loop instead of requiring an additional LLM call.” Messages expose content_blocks, one way to read modern model features across providers. And legacy chains, retrievers and the hub moved to langchain-classic, so old imports change from langchain.chains to langchain_classic.chains.
03 · The graph: what you define

Source: LangGraph Graph API docs.
Under the agent layer sits the graph. The docs sum it up as “nodes do the work, edges tell what to do next.” A graph has three parts:
- State is a typed schema, usually a
TypedDict. Each key has its own reducer, which decides how updates merge:add_messagesappends to a message list, and a key with no reducer is overwritten by the latest write. - Nodes are plain functions, sync or async, that read the state and return an update.
- Edges decide what runs next:
add_edgefor a fixed step,add_conditional_edgesfor a routing function.
Seven lines build the same loop that create_agent gives you:
builder = StateGraph(State)
builder.add_node("model", call_model)
builder.add_node("tools", run_tools)
builder.add_edge(START, "model")
builder.add_conditional_edges("model", route)
builder.add_edge("tools", "model")
graph = builder.compile(checkpointer=saver)
Three helpers cover the rest of routing. Send fans work out to the same node with different inputs, map-reduce style. Command updates the state and jumps to a node in one return value. A subgraph is a compiled graph used as a node: added directly, it shares state keys with the parent; called inside a node, it keeps its own schema. Either way each subgraph has its own checkpoint namespace, so the parent may not see its updates right away.
The same runtime has two front ends. The Graph API draws an explicit graph, which suits branching, parallel paths that merge, and teams that read diagrams. The Functional API (@entrypoint, @task) keeps ordinary Python control flow and suits linear code you do not want to rewrite, though it cannot be visualized. “Both APIs share the same underlying runtime.”
04 · The runtime: one super-step at a time

Source: LangGraph runtime (Pregel) docs.
Compiling a graph produces a Pregel instance, the runtime. It follows the Bulk Synchronous Parallel model, which its author chose because it “provides deterministic concurrency, with full support for loops.” Each super-step has three phases:
- Plan: pick the nodes triggered by channels that changed in the previous step.
- Execute: run them in parallel. “Channel updates are invisible to actors until the next step.”
- Update: apply the writes to the state channels through their reducers.
The loop repeats until no node is triggered or the recursion limit is reached. Nodes that run in parallel belong to the same super-step. This is why two parallel nodes writing to the same key without a reducer fail with INVALID_CONCURRENT_GRAPH_UPDATE: the default channel accepts one value per step.
Set the recursion limit explicitly in config and watch it with RemainingSteps. Do not rely on the default: the documentation and the code currently give different numbers.
05 · Memory: checkpoints, threads and the store

Source: LangGraph persistence and checkpointer docs.
A checkpointer saves the state at each super-step boundary under a thread_id, the primary key of a conversation. That single mechanism gives four features: resume after a crash, human approvals, conversation memory and time travel. If one node in a step fails, the writes of the nodes that finished are kept as pending writes, so a resume runs only the failed one.
| Durability mode | When it writes | If the process dies |
|---|---|---|
exit | Only when the run ends | Mid-run state is lost |
async (default) | While the next step runs | The last step may be lost |
sync | Before the next step starts | Every finished step is saved, at some latency cost |
InMemorySaver and SQLite are for development; the docs call PostgresSaver “ideal for using in production.” Run setup() as a migration step, keep thread_id under 255 characters, and prune old checkpoints, because “over long conversations, checkpoints accumulate.” By default every checkpoint stores every channel in full; DeltaChannel, in beta since 1.2, stores only the changes.
The store is the second kind of memory: long-term data shared across threads, addressed by a namespace and a key, with optional semantic search. Threads remember a conversation; the store remembers a user.
Time travel lets you replay or fork any checkpoint. Replay “re-executes nodes—it doesn’t just read from cache,” so model and API calls fire again.
06 · Human in the loop

Source: LangGraph interrupts docs.
interrupt(payload) pauses the graph, saves the state and returns the payload to the caller. Hours or days later, graph.invoke(Command(resume=value), config) with the same thread_id continues the run, and value becomes the return value of interrupt().
The catch is in the docs: “the runtime restarts the entire node from the beginning—it does not resume from the exact line where interrupt was called.” An email sent before interrupt() goes out twice. Five rules follow:
- Make side effects before
interrupt()idempotent, or move them after it. - Never wrap
interrupt()in try/except: the pause is an exception, and catching it swallows the pause. - Keep the order of several interrupts in a node fixed; resume values match by index.
- Avoid
interrupt()inside awhileloop: each resume replays every earlier iteration. - Use static breakpoints (
interrupt_before,interrupt_after) for debugging only.
07 · Streaming and failures
Streaming exposes the same loop: values (the full state after each step), updates (what each node changed), messages (LLM tokens), custom (your own events) and, with a checkpointer, checkpoints and tasks. LangGraph 1.2 added event streaming with typed projections, which the docs recommend for new applications.
Failures get different tools by type, in a table the docs give directly: transient errors such as network blips and rate limits get a RetryPolicy on the node; errors the model can fix go into the state and loop back; errors a user must fix pause with interrupt(); unexpected errors bubble up. Since 1.2, a node can also have a timeout (async nodes only) and an error_handler that runs after retries run out. Interrupts bypass both the retries and the error handler.
08 · Deep Agents and deployment

Source: LangSmith Agent Server and standalone deployment docs.
Deep Agents is a harness on top of LangGraph for long, open-ended work: “planning, subagents, filesystem tools, and context management.” In a LangChain case study, Rippling runs a supervisor with subagents on it for more than a million users.
Deployment goes through LangSmith Agent Server. PostgreSQL is the system of record for assistants, threads, runs, checkpoints and the store; Redis “handles the signaling, cancellation, and streaming pub/sub” and keeps no run data. Stateless API servers create runs; stateless queue workers claim them, with at most one active run per thread. Inside Agent Server you do not configure a checkpointer in code: the server provides one.
The library is MIT, but hosting is not. Cloud deployment needs a paid LangSmith plan, and even a standalone self-hosted server needs a LangSmith license key. The server authenticates the key once at startup and, unless it runs air-gapped, needs outbound access to beacon.langchain.com for license verification and usage reporting. You can also skip Agent Server entirely and run the graph inside your own service with your own Postgres checkpointer.
09 · Where it bites, and when to take it
The documentation itself lists most of the traps:
Commandplus a static edge runs both routes. “Commandonly adds dynamic edges—static edges defined withadd_edgestill execute.”- Running threads pick up new code. “LangGraph applies the latest graph immediately to every thread.” Renaming or removing a node breaks threads paused on it; make new state fields optional and rename by adding first and removing later.
- Replay is not a cache. Model and API calls run again.
- Checkpoints are an attack surface.
langchain-corehad a CVSS 9.3 serialization flaw fixed in 1.2.5.langgraph-checkpointfixed an RCE in its JSON serializer in 3.0.0 (CVE-2025-64439, triggered when untrusted data is saved into checkpoints) and a deserialization flaw in 4.1.1 (CVE-2026-48775, which needs write access to the store). Upgrade tolanggraph1.2.16, which requireslanggraph-checkpoint4.3.0 or later andlangchain-core1.4.7 or later, or pinlanggraph-checkpointto 4.1.1 or later; restrict write access and encrypt checkpoints.
Independent engineers add one more risk: the framework becomes a layer between your code and your business logic. LinkedIn’s engineers put an adapter layer over LangGraph for their hiring agent so they can switch frameworks relatively cheaply. In our CRM, AgenticCRM, the chat agent runs on a LangGraph StateGraph.
Take it for long runs that must survive a crash, human approval in the middle of a process, and many long threads. Skip it for a few sequential calls: Nuno Campos, who built the runtime, writes that “the biggest competitor to any code framework is always no framework.”
Five settings to make explicit before production:
PostgresSaverwithsetup()as a migration and a pruning job.- A
durabilitymode chosen per graph,syncwhere a lost step costs money. - An explicit
recursion_limit. - A
RetryPolicyon every node that calls an external service. - Optional new state fields, so paused threads still load after a deploy.
For the other side of the comparison, read our guide to the OpenAI Agents SDK, part by part.
FAQ
What is the difference between LangChain and LangGraph in 2026? LangGraph is the runtime: state, graphs, checkpoints, interrupts and streaming. LangChain 1.x is the agent layer on top: create_agent, middleware, models, tools and messages. create_agent returns a compiled LangGraph graph, so a LangChain agent runs on the LangGraph runtime.
What is a super-step in LangGraph? One iteration of the Pregel-style runtime: plan which nodes to run, execute them in parallel with their writes hidden from each other, then apply the writes to state channels. Nodes that run in parallel belong to the same super-step, and the checkpoint is saved at its boundary.
Why does my LangGraph node run twice after an approval? Because on resume the runtime restarts the whole node from the top, not from the line where interrupt() was called. Code before interrupt() runs again, so side effects there must be idempotent.
Do I need LangSmith to run LangGraph in production? Not for the library: LangGraph is MIT and runs with your own Postgres checkpointer. You need LangSmith for its tracing and evals, and for Agent Server deployment: even a self-hosted standalone Agent Server requires a LangSmith license key.
When should I not use LangGraph? For a few sequential model calls you can write as a plain loop. Nuno Campos, who built the runtime, writes that the biggest competitor to any code framework is no framework. Take it when you need resume after a crash, human approval in the middle of a run, or many long-running threads.