LangGraphLangGraph 1.2 · Python 3.10+
Dashboard
0%
1
Curious builder0 XP earned · 300 to level 2
0 daysFinish a lesson to begin
Badge collection0 of 6 unlocked
38 small wins to finish your pathNext lesson →

Checkpointer

A checkpointer saves the state after every step. Give a run a thread_id and the next run on the same thread continues where the last one left off.

Last updated: 29 Sep, 2026 · LangGraph 1.2

Without a checkpointer every run starts from nothing. With one, a conversation carries across turns, which is what makes a chat feel like it remembers you.

Adding a MemorySaver checkpointer at compile · from the Complete Agentic AI Course In 10 Hours · 240:58 to 244:32

Remembering a name with MemorySaver

Without memory the video's agent forgets between invokes. Told "Hello my name is Krish" and then asked "What is my name", it cannot say; in the video's run it even makes a tool call before apologizing. The fix is a checkpointer. MemorySaver, from langgraph.checkpoint.memory, saves the state after every node. It goes into compile(checkpointer=memory).

A thread_id in the config, and the name remembered · from the Complete Agentic AI Course In 10 Hours · 244:32 to 248:12

Every invoke then passes a config with a thread_id, the id of one conversation. On thread "1" the second question gets the name back.

The video imports MemorySaver, which is another name for InMemorySaver, the name the docs and the shop's code below use. The video's graph with memory runs below on Groq with both of its tools: tool, the TavilySearch from ToolNode and tools_condition, which needs langchain-tavily and TAVILY_API_KEY, and multiply. It is a complete script: save it as its own file, such as memory_graph.py, and set GROQ_API_KEY and TAVILY_API_KEY first (add the load_dotenv() lines at the top if they are in .env).

ExampleAPI keyFrom the video, run on Groq
from typing import Annotated
from typing_extensions import TypedDict
from langgraph.graph import StateGraph,START,END
from langgraph.graph.message import add_messages
from langgraph.prebuilt import ToolNode, tools_condition
from langchain.chat_models import init_chat_model
from langchain_tavily import TavilySearch
from langgraph.checkpoint.memory import MemorySaver

class State(TypedDict):
    messages:Annotated[list,add_messages]

llm=init_chat_model("groq:openai/gpt-oss-120b")

tool=TavilySearch(max_results=2)

## Custom function
def multiply(a:int,b:int)->int:
    """Multiply a and b

    Args:
        a (int): first int
        b (int): second int

    Returns:
        int: output int
    """
    return a*b

tools=[tool,multiply]
llm_with_tool=llm.bind_tools(tools)

## Node definition
def tool_calling_llm(state:State):
    return {"messages":[llm_with_tool.invoke(state["messages"])]}

## Grpah
builder=StateGraph(State)
builder.add_node("tool_calling_llm",tool_calling_llm)
builder.add_node("tools",ToolNode(tools))

## Add Edges
builder.add_edge(START, "tool_calling_llm")
builder.add_conditional_edges("tool_calling_llm",tools_condition)
builder.add_edge("tools","tool_calling_llm")

memory = MemorySaver()
graph=builder.compile(checkpointer=memory)

config={"configurable":{"thread_id":"1"}}

response=graph.invoke({"messages":"Hi my name is Krish"},config=config)
print(response['messages'][-1].content)

response=graph.invoke({"messages":"Hey what is my name"},config=config)
print(response['messages'][-1].content)

The second invoke sent only "Hey what is my name". The checkpointer handed back the first turn from thread "1", so the model read the name from the conversation. The shop's version below adds a second thread that has no such history.

Compiling with a checkpointer

python
from langgraph.checkpoint.memory import InMemorySaver

graph = builder.compile(checkpointer=InMemorySaver())
config = {"configurable": {"thread_id": "1"}}
graph.invoke(inputs, config)   # saved under thread "1"

The graph has one node that calls the model. Build it one piece at a time.

The imports

Start with the imports: the graph pieces, the in-memory checkpointer, the model builder, and the message types.

python
from langgraph.graph import MessagesState, StateGraph, START, END
from langgraph.checkpoint.memory import InMemorySaver   # saves state per thread
from langchain.chat_models import init_chat_model
from langchain.messages import HumanMessage, SystemMessage

The model node

Define one node that sends the conversation so far to the model and appends its reply.

python
model = init_chat_model("groq:openai/gpt-oss-120b", temperature=0)  # uses your GROQ_API_KEY
SYSTEM = SystemMessage("You are the support assistant for a small online shop. Answer in one short sentence.")

def reply(state: MessagesState):
    return {"messages": [model.invoke([SYSTEM] + state["messages"])]}

Building the graph

Build the graph and compile it with a checkpointer. That one argument is what turns on memory.

python
builder = StateGraph(MessagesState)
builder.add_node("reply", reply)
builder.add_edge(START, "reply")
builder.add_edge("reply", END)
graph = builder.compile(checkpointer=InMemorySaver())   # memory turned on
  • add_edge(START, "reply") runs the node first.
  • compile(checkpointer=InMemorySaver()) saves the state after every step.

Running two turns

Tell the model your name on turn 1, ask for it on turn 2 on the same thread, then ask again on a new thread. Print how many messages each state holds and the model's answer.

python
cfg = {"configurable": {"thread_id": "1"}}
graph.invoke({"messages": [HumanMessage("My name is Ravi.")]}, cfg)           # turn 1
out = graph.invoke({"messages": [HumanMessage("What is my name?")]}, cfg)     # turn 2, same thread
print(len(out["messages"]), out["messages"][-1].content)

other = {"configurable": {"thread_id": "2"}}                                   # a new thread
new = graph.invoke({"messages": [HumanMessage("What is my name?")]}, other)
print(len(new["messages"]), new["messages"][-1].content)

The checkpointer in a run

The same pieces in one file.

ExampleAPI key
from langgraph.graph import MessagesState, StateGraph, START, END
from langgraph.checkpoint.memory import InMemorySaver
from langchain.chat_models import init_chat_model
from langchain.messages import HumanMessage, SystemMessage

model = init_chat_model("groq:openai/gpt-oss-120b", temperature=0)  # uses your GROQ_API_KEY
SYSTEM = SystemMessage("You are the support assistant for a small online shop. Answer in one short sentence.")

def reply(state: MessagesState):
    return {"messages": [model.invoke([SYSTEM] + state["messages"])]}

builder = StateGraph(MessagesState)
builder.add_node("reply", reply)
builder.add_edge(START, "reply")
builder.add_edge("reply", END)
graph = builder.compile(checkpointer=InMemorySaver())

cfg = {"configurable": {"thread_id": "1"}}
graph.invoke({"messages": [HumanMessage("My name is Ravi.")]}, cfg)           # turn 1
out = graph.invoke({"messages": [HumanMessage("What is my name?")]}, cfg)     # turn 2, same thread
print(len(out["messages"]), out["messages"][-1].content)

other = {"configurable": {"thread_id": "2"}}                                   # a new thread
new = graph.invoke({"messages": [HumanMessage("What is my name?")]}, other)
print(len(new["messages"]), new["messages"][-1].content)

Why thread 1 remembered and thread 2 did not

  • Turn 1 saved a human and an AI message under thread "1".
  • Turn 2 used the same thread_id, so it loaded those two first. The model saw "My name is Ravi." in the conversation and answered from it, and the state ended with four messages.
  • Thread "2" had nothing saved, so it started with only the new question: two messages, and the model had no name to give.

With and without a checkpointer

No checkpointerWith checkpointer
Each runStarts from nothingContinues its thread
MemoryNone across runsPer thread_id
NeedsNothingA thread_id in config

When you need a checkpointer

  • Any chat that should remember earlier turns.
  • Any run you want to pause and resume, which needs the state saved.
Watch out. InMemorySaver keeps checkpoints in RAM and loses them on restart. For anything real use SqliteSaver or PostgresSaver; the saving code is identical.
Try it yourself
  • Call graph.get_state(cfg) and read the saved messages for thread "1".
  • Compile the same graph without the checkpointer and run the two turns again. What does the model answer on turn 2?
Previouscreate_agent

You understood something today that you didn't yesterday.