Memory#

Langgraph is designed to graph all events that occur within the graph. This section considers options for setting up and using the graph’s memory.

from langgraph.graph import StateGraph, START, END
from langgraph.checkpoint.memory import InMemorySaver

Get state#

You can obtain a state of the graph compiled with the checkpointer using get_state method.


The following cell creates a graph with a checkpointer and invokes it.

graph = (
    StateGraph(dict)
    .add_edge(START, END)
    .compile(checkpointer=InMemorySaver())
)


config = {"configurable": {"thread_id": 1}}
graph.invoke(dict(val=10), config=config)
{'val': 10}

The following cell shows the output of the get_config method.

graph.get_state(config)
StateSnapshot(values={'val': 10}, next=(), config={'configurable': {'thread_id': '1', 'checkpoint_ns': '', 'checkpoint_id': '1f103ad4-ee84-66ec-8000-9714b3e06ad8'}}, metadata={'source': 'loop', 'step': 0, 'parents': {}}, created_at='2026-02-06T22:43:51.326683+00:00', parent_config={'configurable': {'thread_id': '1', 'checkpoint_ns': '', 'checkpoint_id': '1f103ad4-ee82-6612-bfff-fae2fc12e19c'}}, tasks=(), interrupts=())

Get history#

You can retrieve the history of the updates of the state by invoking the get_state_history method of the graph. All StateSnapshot-s are saved in the checkpointer, and you can iterate over them.


The following cell creates a simple recursive graph that produces new states until the “value” reaches 4.

def condition(state: dict) -> str:
    if state["value"] >= 4:
        return "end"
    return "next"


def update(state: dict) -> dict:
    return {"value": state["value"] + 1}


graph = (
    StateGraph(dict)
    .add_node("update", update)
    .add_edge(START, "update")
    .add_conditional_edges(
        source="update",
        path=condition,
        path_map={"end": END, "next": "update"}
    )
    .compile(checkpointer=InMemorySaver())
)

As expected, the invocation of the graph returns a value of 4.

config = {"configurable": {"thread_id": 1}}
graph.invoke(dict(value=0), config=config)
{'value': 4}

The following cell iterates through the history of the state updates and displays their values.

for state_check_point in graph.get_state_history(config):
    print(state_check_point.values)
{'value': 4}
{'value': 3}
{'value': 2}
{'value': 1}
{'value': 0}
None

Replay#

To replay a graph, pass the configuration of the state you want the replay to start from to the invoke or stream method of the graph.


The following cell creates a graph produces a different result each time.

import random


def node(state: dict) -> dict:
    return {"value": random.random()}


graph = (
    StateGraph(dict)
    .add_node("node", node)
    .add_edge(START, "node")
    .add_edge("node", END)
    .compile(checkpointer=InMemorySaver())
)

config = {"configurable": {"thread_id": 1}}
graph.invoke({}, config=config)
{'value': 0.8807058489606071}

The following cell retrieves some state information from the thread’s history.

to_replay = list(graph.get_state_history(config))[0]

Invoking the graph with config from the selected state leads to the same result because it is not a reinvocation of the graph; it is a replay of a thread that has already been executed.

graph.invoke(None, config=to_replay.config)
{'value': 0.8807058489606071}

Update state#

The update_state method creates a new check point in the graph history that contains the modified state.


The following cell creates a graph that increments the val attribute of the state twice.

def node(state: dict) -> dict:
    return dict(val=state["val"] + 1)


graph = (
    StateGraph(dict)
    .add_node("a", node)
    .add_node("b", node)
    .add_edge(START, "a")
    .add_edge("a", "b")
    .add_edge("b", END)
    .compile(checkpointer=InMemorySaver())
)

The result of the graph invokation is represented.

config = {"configurable": {"thread_id": 1}}
graph.invoke(
    dict(val=1),
    config=config
)
{'val': 3}

The history of the thread is represented in the following cell.

for state_snapshot in graph.get_state_history(config):
    print(state_snapshot.config["configurable"])
{'thread_id': '1', 'checkpoint_ns': '', 'checkpoint_id': '1f103ad5-d02f-626e-8002-de700dd95ed5'}
{'thread_id': '1', 'checkpoint_ns': '', 'checkpoint_id': '1f103ad5-d02d-6a2b-8001-ab698db455eb'}
{'thread_id': '1', 'checkpoint_ns': '', 'checkpoint_id': '1f103ad5-d029-6cd6-8000-169999fbcec1'}
{'thread_id': '1', 'checkpoint_ns': '', 'checkpoint_id': '1f103ad5-d026-672a-bfff-9bbee7b5dc95'}

It contains 4 snapshots.

Let’s take an intermediate, snapshot which will contain the state after the first increment.

state_snapshot = list(graph.get_state_history(config))[1]
state_snapshot.values
{'val': 2}

The following cell runs the update_state method. The configuration of the selected state specifies which states need to be modified.

new_config = graph.update_state(
    values={"val": 5},
    config=state_snapshot.config
)
new_config
{'configurable': {'thread_id': '1',
  'checkpoint_ns': '',
  'checkpoint_id': '1f103ad5-f1f7-6620-8002-76e4aea31e92'}}

The result is a new snapshot config that is actually appended to the graph history:

for state_snapshot in graph.get_state_history(config):
    print(state_snapshot.config["configurable"])
{'thread_id': '1', 'checkpoint_ns': '', 'checkpoint_id': '1f103ad5-f1f7-6620-8002-76e4aea31e92'}
{'thread_id': '1', 'checkpoint_ns': '', 'checkpoint_id': '1f103ad5-d02f-626e-8002-de700dd95ed5'}
{'thread_id': '1', 'checkpoint_ns': '', 'checkpoint_id': '1f103ad5-d02d-6a2b-8001-ab698db455eb'}
{'thread_id': '1', 'checkpoint_ns': '', 'checkpoint_id': '1f103ad5-d029-6cd6-8000-169999fbcec1'}
{'thread_id': '1', 'checkpoint_ns': '', 'checkpoint_id': '1f103ad5-d026-672a-bfff-9bbee7b5dc95'}

Using this config leads to the graph begin resumed from the modified state.

graph.invoke(None, config=new_config)
{'val': 6}

The thread history shows all the states generated by resuming.

for state_snapshot in graph.get_state_history(config):
    print(state_snapshot.config["configurable"])
{'thread_id': '1', 'checkpoint_ns': '', 'checkpoint_id': '1f103ad6-1f78-6502-8003-e5602bd35a1e'}
{'thread_id': '1', 'checkpoint_ns': '', 'checkpoint_id': '1f103ad5-f1f7-6620-8002-76e4aea31e92'}
{'thread_id': '1', 'checkpoint_ns': '', 'checkpoint_id': '1f103ad5-d02f-626e-8002-de700dd95ed5'}
{'thread_id': '1', 'checkpoint_ns': '', 'checkpoint_id': '1f103ad5-d02d-6a2b-8001-ab698db455eb'}
{'thread_id': '1', 'checkpoint_ns': '', 'checkpoint_id': '1f103ad5-d029-6cd6-8000-169999fbcec1'}
{'thread_id': '1', 'checkpoint_ns': '', 'checkpoint_id': '1f103ad5-d026-672a-bfff-9bbee7b5dc95'}