Skip to course content
Free LangGraph course

LangGraph for Agentic Workflows

Unit 02.00: State is the thing that actually moves

Nodes do not call each other. They read state and return updates to it, and the state is the only thing travelling through the graph.

Partial updates, merged by the framework

A node receives the whole state and returns a dictionary of the fields it changed. LangGraph merges that into the state and passes the result to whatever runs next.

The code runs a two-node graph and prints the final state.

from typing import TypedDict
from langgraph.graph import StateGraph, START, END


class State(TypedDict):
    question: str
    findings: list
    answer: str


def research(state: State):
    return {"findings": ["source A", "source B"]}


def write(state: State):
    return {"answer": f"{state['question']} -> {len(state['findings'])} sources"}


g = StateGraph(State)
g.add_node("research", research)
g.add_node("write", write)
g.add_edge(START, "research")
g.add_edge("research", "write")
g.add_edge("write", END)

final = g.compile().invoke({"question": "what changed?", "findings": [], "answer": ""})
for k, v in final.items():
    print(f"{k:10} {v}")

# Each node returns a partial update, not the whole state. LangGraph merges it.
# That is why `research` never mentions `question` -- it did not change it, so
# it does not return it.

Notice what research returns: only findings. It never mentions question, because it did not change it. Returning the whole state would work and would be worse - the next reader cannot tell which fields the node is responsible for.

That convention is also what makes nodes testable in isolation. A node is a function from state to a partial update, so a test is a dictionary in and a dictionary out, with no graph involved.

The mistake this prevents

The mistake is mutating the state dictionary in place instead of returning an update. It appears to work, and it breaks checkpointing and any reducer-based merging, because the framework compares what you returned against what it held. Always return; never mutate.

Takeaway

State is the only thing that moves between nodes. Each node returns a partial update naming exactly the fields it owns, which is what makes the graph inspectable and the node testable.