By Sagar Shankaran, Founder of CallSphere
Implement persistence and time travel in LangGraph using MemorySaver, SqliteSaver, and PostgresSaver to checkpoint agent state, replay past executions, and recover from failures.
Key takeaways
Without checkpointing, a LangGraph workflow is ephemeral. If the process crashes mid-execution, all state is lost and you must start over. Checkpointing solves this by saving the graph state after every node execution. This enables three critical capabilities: crash recovery, conversation memory across sessions, and time travel to inspect or replay past states.
The simplest checkpointer stores state in a Python dictionary. It is perfect for development and testing:
flowchart TD
USER(["User input"])
SUPER["Supervisor node<br/>routes by state"]
A["Specialist node A<br/>research"]
B["Specialist node B<br/>writing"]
TOOL{"Tool call<br/>needed?"}
EXEC["Tool executor<br/>ToolNode"]
CHK[("Postgres<br/>checkpointer")]
INT{"interrupt for<br/>human approval?"}
HUMAN(["Human reviewer"])
OUT(["Final response"])
USER --> SUPER
SUPER --> A
SUPER --> B
A --> TOOL
B --> TOOL
TOOL -->|Yes| EXEC --> SUPER
TOOL -->|No| INT
INT -->|Yes| HUMAN --> SUPER
INT -->|No| OUT
SUPER <--> CHK
style SUPER fill:#4f46e5,stroke:#4338ca,color:#fff
style CHK fill:#ede9fe,stroke:#7c3aed,color:#1e1b4b
style OUT fill:#059669,stroke:#047857,color:#fff
style HUMAN fill:#f59e0b,stroke:#d97706,color:#1f2937
from langgraph.checkpoint.memory import MemorySaver
from langgraph.graph import StateGraph, START, END
from typing import TypedDict, Annotated
from langgraph.graph.message import add_messages
class State(TypedDict):
messages: Annotated[list, add_messages]
def echo(state: State) -> dict:
last = state["messages"][-1].content
return {"messages": [{"role": "assistant", "content": f"Echo: {last}"}]}
builder = StateGraph(State)
builder.add_node("echo", echo)
builder.add_edge(START, "echo")
builder.add_edge("echo", END)
memory = MemorySaver()
graph = builder.compile(checkpointer=memory)
All state is lost when the process exits. Use this only for development.
Each conversation gets its own thread ID. This lets multiple users share the same graph instance:
from langchain_core.messages import HumanMessage
# Conversation 1
config1 = {"configurable": {"thread_id": "user-alice"}}
graph.invoke({"messages": [HumanMessage(content="Hi, I'm Alice")]}, config1)
graph.invoke({"messages": [HumanMessage(content="What's my name?")]}, config1)
# Conversation 2 — completely isolated
config2 = {"configurable": {"thread_id": "user-bob"}}
graph.invoke({"messages": [HumanMessage(content="Hi, I'm Bob")]}, config2)
Each thread maintains its own state history. Alice and Bob never see each other's messages.
Hear it before you finish reading
Talk to a live CallSphere AI voice agent in your browser — 60 seconds, no signup.
For persistence that survives process restarts, use the SQLite checkpointer:
from langgraph.checkpoint.sqlite import SqliteSaver
import sqlite3
conn = sqlite3.connect("checkpoints.db", check_same_thread=False)
sqlite_saver = SqliteSaver(conn)
graph = builder.compile(checkpointer=sqlite_saver)
# State persists to disk
config = {"configurable": {"thread_id": "persistent-thread"}}
graph.invoke({"messages": [HumanMessage(content="Remember this")]}, config)
# Later, even after restart, the conversation continues
result = graph.invoke(
{"messages": [HumanMessage(content="What did I say?")]},
config,
)
The SQLite file contains the full state history for every thread, including all intermediate checkpoints.
For production deployments, use PostgreSQL:
from langgraph.checkpoint.postgres import PostgresSaver
DB_URI = "postgresql://user:password@localhost:5432/langgraph_db"
with PostgresSaver.from_conn_string(DB_URI) as pg_saver:
pg_saver.setup() # Creates tables on first run
graph = builder.compile(checkpointer=pg_saver)
config = {"configurable": {"thread_id": "prod-session-123"}}
result = graph.invoke(
{"messages": [HumanMessage(content="Process this order")]},
config,
)
PostgresSaver handles concurrent access, transactions, and connection pooling. Call setup() once to create the required checkpoint tables.
Every node execution creates a checkpoint. You can list and inspect all checkpoints for a thread:
Still reading? Stop comparing — try CallSphere live.
CallSphere ships complete AI voice agents per industry — 14 tools for healthcare, 10 agents for real estate, 4 specialists for salons. See how it actually handles a call before you book a demo.
config = {"configurable": {"thread_id": "my-thread"}}
# Get current state
current = graph.get_state(config)
print("Current messages:", len(current.values["messages"]))
# List all checkpoints (state history)
history = list(graph.get_state_history(config))
for i, state in enumerate(history):
print(f"Checkpoint {i}: {len(state.values['messages'])} messages")
print(f" Created by node: {state.metadata.get('source', 'unknown')}")
You can resume execution from any historical checkpoint by providing its ID:
# Get the second-to-last checkpoint
history = list(graph.get_state_history(config))
past_state = history[2] # Go back two steps
# Resume from that point with new input
past_config = {
"configurable": {
"thread_id": "my-thread",
"checkpoint_id": past_state.config["configurable"]["checkpoint_id"],
}
}
result = graph.invoke(
{"messages": [HumanMessage(content="Try a different approach")]},
past_config,
)
This creates a new branch in the state history. The original checkpoints remain untouched, giving you a full audit trail of every execution path.
MemorySaver adds negligible overhead. SqliteSaver and PostgresSaver add serialization and I/O time proportional to state size. For typical chat agents with dozens of messages, each checkpoint takes a few milliseconds. For agents with very large state objects, consider keeping state lean and storing bulk data externally.
There is no built-in pruning API in the core library. For PostgresSaver, you can write SQL queries to delete checkpoints older than a retention period. For SqliteSaver, you can run a cleanup job against the database file directly.
No. Each saver serializes state in its own format. You cannot migrate checkpoints from SQLite to PostgreSQL directly. If you need to migrate, you would read state from one saver and write it to another programmatically.
#LangGraph #Checkpointing #Persistence #TimeTravel #Python #AgenticAI #LearnAI #AIEngineering

Written by
Sagar Shankaran· Founder, CallSphere
LinkedInSagar Shankaran is the founder of CallSphere, where he builds production AI voice and chat agents deployed across healthcare, hospitality, real estate, and home services. He writes about agentic AI, LLM engineering, and shipping voice agents that handle real calls in production.
See how AI voice agents work for your industry. Live demo available -- no signup required.
How we built a fault-tolerant HVAC emergency triage and tech-dispatch platform on Kubernetes — three-tier CQRS, 11 micro-agents on the OpenAI Agents SDK + LangGraph, NATS JetStream, DTMF/SMS/WebSocket acceptance, circuit breakers, and an evaluation pipeline that catches regressions before they wake a tech at 3 AM.
How short-term (thread-scoped) and long-term (cross-thread) memory actually work in LangGraph, with code, schemas, and the eviction policies that keep cost predictable.
Langgraph multi-agent supervisor handoffs docs: the supervisor pattern in LangGraph for coordinating specialist agents, with full code, an eval pipeline that scores routing accuracy, and the failure modes to watch for.
How to stream tokens, tool-call deltas, and intermediate steps from an agent — with code for both the OpenAI Agents SDK and LangChain — and the gotchas that bite in production.
Build a browser agent with LangGraph and Playwright that does multi-step web tasks, then ground-truth its work with visual diffs and DOM-based evaluators.
Beyond single-shot RAG — agentic RAG with LangGraph that re-retrieves, self-grades, and rewrites queries. With evals that catch silent retrieval drift.
© 2026 CallSphere Inc. All rights reserved.
Made within San Francisco
Watch how CallSphere handles real customer calls, schedules appointments, and processes payments — live.
Try Live DemoBook a DemoCalculate Your ROI