top of page

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

  • 1 day ago
  • 6 min read

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

·····

Recent Posts

See All
bottom of page