Lesson 14 / 29
Checkpointers and Threads
Persist state between runs so a conversation can continue.
A thread is a saved conversation
A checkpointer saves the graph state after every step. When you compile with a checkpointer and invoke with a thread_id in the config, LangGraph loads that thread's saved state, merges your new input through the reducers, runs, and saves again. Different thread IDs are fully separate conversations. This is short-term memory. InMemorySaver is for development and tests; production uses a durable backend (for example the SQLite or Postgres savers). Treat thread IDs as sensitive: derive them from authenticated users and sessions so one user can never load another's thread.
Save state at every step
Checkpointers save state per thread, enabling conversations, resume after failure and replay.
Two users, two threads, run
I ran this offline with langgraph 1.2.12 and langchain-core 1.6.6 in a Python virtual environment. No API key or model is needed because plain Python functions stand in for the model, so the output is repeatable. Alice's second call sees her first message and the bot's reply (3 messages by then), because the thread is remembered. Bob's thread starts fresh.
import operator
from typing import Annotated, TypedDict
from langgraph.graph import StateGraph, START, END
from langgraph.checkpoint.memory import InMemorySaver
class State(TypedDict):
messages: Annotated[list, operator.add] # reducer: new messages are appended to the stored ones
def reply(state):
return {"messages": [f"bot: I have seen {len(state['messages'])} message(s)"]}
g = StateGraph(State)
g.add_node("reply", reply); g.add_edge(START, "reply"); g.add_edge("reply", END)
app = g.compile(checkpointer=InMemorySaver())
alice = {"configurable": {"thread_id": "alice"}}
bob = {"configurable": {"thread_id": "bob"}}
print(app.invoke({"messages": ["alice: hi"]}, alice)["messages"])
print(app.invoke({"messages": ["alice: again"]}, alice)["messages"]) # same thread: history is remembered
print(app.invoke({"messages": ["bob: hello"]}, bob)["messages"]) # new thread: starts fresh
Output:
['alice: hi', 'bot: I have seen 1 message(s)'] ['alice: hi', 'bot: I have seen 1 message(s)', 'alice: again', 'bot: I have seen 3 message(s)'] ['bob: hello', 'bot: I have seen 1 message(s)']
Quick check: What identifies a conversation to the checkpointer?
- The GPU id
- The model name
- The node name
- The thread_id in the run config
Answer
The thread_id in the run config — Each thread_id has its own saved state history.