top of page

LangGraph: Stateful Agents, Checkpointing, Tool Calls, and Workflow Recovery

Sep 4
6 min read

Updated: Sep 7

A chain runs start to finish or it doesn't run at all. LangGraph exists because most real agent workflows need a third option: pause, wait, and pick back up exactly where they left off.

........

  • LangGraph models an agent as a directed graph: nodes are functions that read and update a typed state object, edges define execution order and branching.

  • A checkpointer saves a snapshot of that state after every node executes, organized by thread — the mechanism behind resuming a failed run, pausing for human approval, and time-travel debugging.

  • MemorySaver keeps state in process memory and loses everything on restart; production deployments need SqliteSaver, PostgresSaver, or a Redis-backed saver instead.

  • The interrupt() function pauses a graph mid-execution for human input, relying on the same checkpointing mechanism that recovers from a crash.

  • LangChain's own create_agent() agents are LangGraph runnables underneath — LangGraph is the lower layer, not a competing framework.

··········

⁣⁣⁣⁣⁣⁣⁣⁣⁣⁣⁣⁣

WHAT LANGGRAPH ACTUALLY MODELS.

LangGraph treats an agent as a graph rather than a script, which changes what kind of control a developer has over it.

State is a typed object — commonly a TypedDict — that flows through the graph and accumulates the information the workflow cares about: messages so far, which action comes next, an iteration count, whatever the workflow needs to track.

Nodes are plain functions that receive the current state and return updates to it. A reasoning node might inspect the conversation so far and decide the next action is calling a tool; a tool node executes that call and writes the result back into state.

Edges connect nodes and define execution order, including conditional edges that branch based on what's currently in state — the mechanism behind loops, retries, and multi-path workflows that a simple linear chain can't express.

The framework is explicitly described as low-level: it gives a developer direct control over state, branching, loops, and persistence, rather than relying on the model itself to decide what happens next at every step.

··········

⁣⁣⁣⁣⁣⁣⁣⁣⁣⁣⁣⁤

HOW LANGGRAPH RELATES TO LANGCHAIN.

The two aren't competing options — one sits underneath the other.

LangChain agents built with create_agent() are LangGraph runnables underneath; LangChain provides pre-built agent architectures and model integrations on top of LangGraph's execution engine, not a separate one.

The practical guidance from the maintainers: reach for LangChain when the goal is building an agent quickly with pre-built architectures and standard model integrations. Reach for LangGraph directly when the workflow needs a mix of deterministic and agentic steps, heavy customization, or carefully controlled latency that a pre-built agent loop doesn't allow.

In practice, that means durability and streaming — two of LangGraph's core features — are available to LangChain agents automatically, because they're built on the same underlying graph runtime.

··········

CHECKPOINTING: WHAT ACTUALLY GETS SAVED.

A checkpointer saves a full snapshot of graph state at each super-step — a completed round of node execution — organized into threads identified by a thread ID.

That snapshot is what makes several distinct features possible from one mechanism: resuming after a crash, pausing for a human to approve or reject a step, replaying execution history for debugging, and maintaining conversational memory across separate calls to the same thread.

Without a checkpointer, state exists only for the duration of one running process. A workflow that fetches data, calls a model twice, and formats a report loses everything if the process stops partway through — fine for a demo, a real production risk for anything long-running or side-effecting.

Compiling a graph with a checkpointer attached is what turns those features on; without one, none of durability, human-in-the-loop, or time-travel debugging are available, regardless of how the graph itself is structured.

··········

WHICH CHECKPOINTER TO ACTUALLY USE.

The choice of checkpointer backend is a production-readiness decision, not a configuration detail.

MemorySaver stores state in process memory. It's the right choice for local development and demos, and the wrong choice for anything else — any restart, pod eviction, or redeploy loses every in-flight thread with no recovery path.

SqliteSaver gives a durable backend suited to single-process workloads — state survives a restart of that one process, but doesn't naturally share state across multiple running instances.

PostgresSaver or a Redis-backed saver are the standard choices for multi-process production deployments, where more than one instance of the application needs to read and write the same thread's state consistently.

Custom backends exist too — SAP HANA, FalkorDB, and others implement the same BaseCheckpointSaver interface, which matters for organizations that want agent state co-located with data they already operate rather than in a separate store.

··········

Checkpointer backends by use case

Checkpointer

Survives restart?

Multi-process safe?

Typical use

MemorySaver

No

No

Local development, demos only

SqliteSaver

Yes

No

Single-process production

PostgresSaver

Yes

Yes

Multi-process production

Redis-backed saver

Yes

Yes

Multi-process production, high throughput

··········

RECOVERING FROM A FAILURE: WHERE EXECUTION ACTUALLY RESUMES.

Durable execution means a workflow interrupted by an exception — an LLM provider outage, for instance — can pick back up rather than starting over.

Recovery works by re-invoking the workflow with the same thread identifier and passing None as the input, rather than passing a new request.

Where execution resumes depends on the graph's shape. For a plain StateGraph, it resumes at the beginning of the node where execution stopped — not mid-node. If the halted node was itself a call into a subgraph, resumption starts at the parent node that made that call, and inside the subgraph, at the specific node that was interrupted.

Two design requirements make this reliable rather than fragile: the workflow needs to be deterministic and idempotent, and any side effects or non-deterministic operations — an API call with real-world consequences, a random number, a timestamp — need to be wrapped in tasks rather than run directly inside a node. Skipping that wrapping is the most common way a "durable" workflow turns out not to be.

··········

HUMAN-IN-THE-LOOP: THE SAME MECHANISM, A DIFFERENT TRIGGER.

Pausing for a human and recovering from a crash rely on the identical persistence layer — only what triggers the pause differs.

Calling interrupt() inside a node halts graph execution at that point and persists the paused state through the checkpointer, exactly as a crash would leave state at its last checkpoint.

Resuming after human input uses the same thread-based re-invocation pattern as crash recovery — the graph doesn't need separate code paths for "resume after failure" and "resume after approval."

That shared mechanism is also what enables time-travel debugging: because every super-step is checkpointed, a developer can inspect the full state history of a thread and see exactly what the graph knew at each point, not just its final output.

··········

BUILDING MULTI-AGENT SYSTEMS ON TOP OF THE SAME GRAPH.

LangGraph doesn't need a separate multi-agent framework bolted on — the same node-and-edge model extends to coordinating several agents.

Common patterns include a supervisor node that routes work to specialist agent nodes based on the task, message-passing between agents modeled as edges carrying state updates, and parallel execution where independent nodes run concurrently and their results get aggregated by a downstream node.

Subgraphs let a full agent — with its own nodes, edges, and even its own checkpointing behavior — be embedded as a single node inside a larger graph, which is what makes the resumption rules for nested subgraphs, described above, relevant in practice rather than theoretical.

Tool integration follows the same pattern as any other node: LangGraph works directly with OpenAI's function-calling and tool-use interfaces, and a tool-calling node is just a function that executes the requested tool and writes the result back into state for the next node to read.

··········

PRACTICAL GUIDANCE FOR PRODUCTION USE.

A small set of decisions accounts for most of the gap between a LangGraph demo and a LangGraph system that survives real traffic.

Pick a durable checkpointer backend before going to production, not after the first incident makes the choice for you — MemorySaver has no place outside local development.

Design nodes to be idempotent from the start, and wrap anything with a real-world side effect in a task, so that a resumed execution can't accidentally repeat an action that already happened once.

Use thread IDs deliberately — one thread per logical conversation or workflow instance — since thread identity is what ties a resumed execution back to its correct history.

Reach for LangGraph directly, rather than a pre-built LangChain agent, once a workflow needs conditional branching, multiple cooperating agents, or human approval steps that a standard agent loop doesn't model well.

Treat checkpoint history as a debugging tool from day one — inspecting what state looked like at each super-step is usually faster than reproducing a failure from logs alone.

··········

·····

FOLLOW US FOR MORE.

·····

·····

DATA STUDIOS

·····

bottom of page