langchain-ai / langgraph
LangGraph models agents as graphs with checkpoints, so work can pause and resume
LangGraph is a low-level orchestration framework from LangChain Inc for long-running, stateful agents. It does not hide prompts or choose an architecture. It provides a graph of nodes and edges, a persistence layer that checkpoints state per thread, and interrupts for human review: the machinery agents tend to need once they leave a demo.
WHAT TO KNOW FIRST
- A checkpointer saves graph state per thread, and the thread_id works as a cursor: reuse it to continue, pass a new one to start with empty state.
- A resumed node restarts from its first line, so side effects before interrupt() should be idempotent, and interrupt() must not sit inside a bare try/except.
- In-memory checkpointers lose everything on restart; production needs a durable saver such as PostgresSaver, plus pruning, because checkpoints accumulate.
01Orchestration, kept deliberately low level
The README calls LangGraph a low-level orchestration framework for building, managing and deploying long-running, stateful agents. The overview adds that it focuses entirely on orchestration and does not abstract prompts or architecture. The central benefit, in the project's own framing, is mixing deterministic, hand-coded steps with model-driven steps in one graph, so the predictable parts of a workflow stay predictable and auditable while the model decides only where it should.
LangGraph is built by LangChain Inc but can be used without LangChain. The docs place the pieces this way: LangChain is the agent framework with integrations for models and tools, LangGraph is the orchestration runtime with durable execution, streaming, human-in-the-loop and persistence, and Deep Agents is a higher-level harness built on LangGraph for planning, subagents and file system tools. The README credits Pregel and Apache Beam as inspiration and NetworkX for the shape of the public interface.
02State, nodes and edges
A LangGraph program defines a state schema, nodes that read and update that state, and edges that decide what runs next. The overview's hello-world builds a StateGraph over MessagesState, adds one node, connects it from START and to END, compiles the graph and invokes it with a user message. The quickstart then builds a calculator agent twice, once with the Graph API and once with the Functional API, defining tools, a model node, a tool node and the logic that decides when to stop.
The state schema is the contract everything else depends on. Keep it small, name fields for what they mean in the domain, and avoid placing large documents in it, since checkpointers persist graph state snapshots. Routing between nodes should live in plain functions that take state and return the next step, which keeps that logic testable without a model in the loop. A graph that can be drawn and explained is easier to debug than an agent loop whose control flow lives inside prompts.
03Checkpointers and stores
The persistence docs describe two systems. Checkpointers save a thread's graph state as checkpoints, which serves conversation continuity, human-in-the-loop workflows, time travel and fault tolerance. Stores hold application-defined data across threads, such as user preferences and shared facts. A graph compiles with either or both, and every call that should continue a conversation passes a thread_id in its configuration. Reusing a thread_id resumes the same checkpoint; a new value starts a new thread with empty state.
The troubleshooting notes are worth reading before production. InMemorySaver keeps checkpoints in RAM and loses them on restart, so durable work needs a persistent checkpointer such as PostgresSaver, with SqliteSaver suggested for local development. With the PostgreSQL saver, thread_id values must stay under 255 characters. Checkpoints accumulate over long conversations and add latency and storage cost, so plan pruning or a retention policy. Subgraphs keep their own checkpoint namespaces, which affects what a parent graph can see.
04Interrupts pause for a person
Human-in-the-loop works through interrupt(). A node calls it with a JSON-serializable value, the runtime saves state through the checkpointer and surfaces the value to the caller, and execution waits. The caller resumes by invoking the graph again on the same thread with Command(resume=...), and that value becomes the return value of interrupt() inside the node. A response schema can validate the human's answer as a Pydantic model, a TypedDict or a dataclass.
This makes approval steps a normal part of the graph. A node can ask whether a refund, an email or a database change should go ahead, and the graph waits without holding a process open, because the state sits in the checkpointer. Durable storage matters even more here, since an approval that waits for a day has to survive deploys and restarts. Decide what the user sees while waiting, who may resume a thread, and what happens to threads nobody answers.
05The rules that catch people out
The interrupts page lists rules that follow from how interrupts are implemented. interrupt() pauses execution by raising a special exception, so wrapping it in a bare try/except swallows the pause; catch specific exception types instead, or keep error-prone code apart from the interrupt. When a node resumes, the runtime restarts the whole node from the beginning, not from the line where interrupt() was called, so any code before it runs again. Side effects placed before an interrupt should therefore be idempotent.
The same page warns against a while True loop that calls interrupt() repeatedly inside one node, because every resume replays all earlier iterations. In practice, put the interrupt at the start of a node or in a node of its own, perform side effects after the human decision, and use idempotency keys for anything that charges money or sends messages. The docs also note that Command(resume=...) is the only Command pattern meant as input to invoke or streaming calls; the other Command parameters are for returning from nodes.
- Keep interrupt() out of broad exception handlers.
- Move side effects after the approval, or make them safe to repeat.
- Use one interrupt per node instead of a loop of interrupts.
06Durable execution and deployment
The README lists durable execution first among its reasons to use LangGraph: agents that persist through failures, run for extended periods and resume from where they left off. The persistence layer is what provides it. For deployment, the docs point to LangSmith Deployment, LangChain's platform for long-running, stateful workflows, and note that its Agent Server handles checkpointers and stores without manual configuration. LangSmith also covers tracing and evaluation, switched on with LANGSMITH_TRACING and an API key.
None of that is required. A LangGraph application can run inside an ordinary Python service with a PostgreSQL checkpointer, and some teams will prefer that to adopting a hosted platform. Whichever route is chosen, trace every run somewhere, store the model and prompt versions with each thread, and make it possible to inspect a stuck thread's checkpoint. Long-running agents fail in ways that surface days later, and the checkpoint history is the evidence.
07Packages and versions move quickly
The repository is a monorepo whose packages are released separately, including langgraph itself, the checkpoint libraries, a PostgreSQL checkpointer, the SDK, the CLI and prebuilt components. The GitHub releases API listed 1.2.18 as the latest langgraph release, published October 26, 2026, the same day as checkpoint 4.3.1 and SDK 0.4.10. Its notes include a change to how often DeltaChannel takes a full snapshot, from every 1,000 updates to every 100, with a parameter to keep the old behavior.
A change like that alters storage use and read speed without touching application code, which is why the checkpoint packages deserve the same pinning as the core library. Pin langgraph and the checkpointer together, read the release notes for both, and test upgrades against a copy of real checkpoints, since a new version must still read state written by the old one. A JavaScript and TypeScript implementation, LangGraph.js, lives in a separate repository, and this site's LangChain.js guide covers the wider JavaScript framework.
08When to reach for it
LangGraph earns its place when an agent has real structure: several steps, branches, retries, long waits and approvals, and a need to explain afterwards what happened. Its MIT license and Python-first design make it easy to adopt inside an existing service. Teams already using Temporal for durable workflows will recognize the concern with saved state and replay, though LangGraph is centered on agent steps and model calls rather than general business workflows.
For a single model call with a couple of tools it adds concepts that are not needed yet, and the docs themselves point people who want a higher-level start toward LangChain's agents or Deep Agents. Begin with one graph, a durable checkpointer and one interrupt, and add structure only when the workflow asks for it.
A SENSIBLE FIRST HOUR
Start small enough to learn the repo
- Install with pip install -U langgraph or uv add langgraph, and add langchain only if you want its model and tool integrations; the docs say LangGraph does not require LangChain.
- Run the hello-world graph from the overview: a StateGraph over MessagesState with one node, edges from START and to END, compile, then invoke it with one user message.
- Compile the same graph with an InMemorySaver checkpointer, invoke it twice with the same thread_id in the config and once with a new thread_id, and compare the state each run sees.
- Add one interrupt() that asks for approval, resume it with Command(resume=True), and confirm that code before the interrupt runs again on resume before using interrupts around side effects.
SOURCE LEDGER
What this review is built on
We use the project repository and first-party documentation. Access, licenses and project direction can change, so recheck the linked source before making a production decision.