Time Travel

Status: ACTIVE (pulled from docs.langchain.com) Source: https://docs.langchain.com/oss/python/langgraph/use-time-travel Timestamp: 2026-05-11

LangGraph supports time travel through checkpoints: replay past executions and fork to explore alternative paths.

Replay

Retry from a prior checkpoint:

# 1. Run the graph
config = {"configurable": {"thread_id": "1"}}
graph.invoke({}, config)

# 2. Find a checkpoint to replay from
history = list(graph.get_state_history(config))

# 3. Find specific checkpoint (e.g., before "write_joke" node)
before_joke = next(s for s in history if s.next == ("write_joke",))

# 4. Replay from that checkpoint
replay_result = graph.invoke(None, before_joke.config)

Fork

Branch from a prior checkpoint with modified state:

# Find checkpoint before write_joke
before_joke = next(s for s in history if s.next == ("write_joke",))

# Fork: update state to change the topic
fork_config = graph.update_state(
    before_joke.config,
    values={"topic": "chickens"},
)

# Resume from the fork
fork_result = graph.invoke(None, fork_config)

Fork from a Specific Node

fork_config = graph.update_state(
    before_joke.config,
    values={"topic": "chickens"},
    as_node="generate_topic",  # Act as if this node produced these values
)

Interrupts and Time Travel

If your graph uses interrupt(), interrupts are always re-triggered during time travel:

# Replay to an interrupt
replay_result = graph.invoke(None, before_ask.config)  # Pauses at interrupt

# Fork and resume with different answer
fork_config = graph.update_state(before_ask.config, {"value": ["forked"]})
graph.invoke(None, fork_config)  # Pauses at interrupt
graph.invoke(Command(resume="Bob"), fork_config)  # Resumes

Multiple Interrupts

Time travel can fork between multiple interrupt points:

# Find checkpoint between ask_name and ask_age interrupts
between = [s for s in history if s.next == ("ask_age",)][-1]

# Fork from between the two interrupts
fork_config = graph.update_state(between.config, {"value": ["modified"]})
result = graph.invoke(None, fork_config)
# ask_name result preserved, ask_age pauses at interrupt

Subgraphs and Time Travel

Inherited checkpointer (default): Parent treats entire subgraph as single super-step. Cannot time travel to points inside subgraph.

Subgraph checkpointer: Set checkpointer=True on subgraph to get its own checkpoint history, enabling time travel from specific points inside it.

subgraph = (
    StateGraph(State)
    .add_node("step_a", step_a)
    .add_node("step_b", step_b)
    ...
    .compile(checkpointer=True)
)

# Access subgraph checkpoint
parent_state = graph.get_state(config, subgraphs=True)
sub_config = parent_state.tasks[0].state.config

fork_config = graph.update_state(sub_config, {"value": ["forked"]})
result = graph.invoke(None, fork_config)