The state schema is the contract every node reads and writes, so designing it well shapes the whole app.
Every LangGraph application starts with its state: the data that flows through the graph and that every node can see. You describe its shape with a TypedDict, a class that declares which keys a dictionary has and their types:
class State(TypedDict):
question: str
answer: strThen you create a builder: builder = StateGraph(State). A builder is an object you configure step by step (adding nodes and edges) before turning it into something runnable.
How state moves:
- Each node receives the current state.
- A node returns a partial update: a dict with only the keys it wants to change.
- LangGraph merges that update into the state, and the next node sees the result.
So nodes don't need to copy the whole state; they just say what changed. By default a returned value replaces the old value of that key. The next-but-one lesson shows how to make a key accumulate instead.
Design tips:
- Store raw facts (the question, retrieved documents, the model's reply), not formatted prompts. Build prompts inside nodes when needed.
- Keep it small and serializable (plain data that can be saved), because later LangGraph will save it after every step.
- You can also use a Pydantic model or a dataclass for the state if you want validation or defaults.
Example
from typing import TypedDict
from langgraph.graph import StateGraph
class State(TypedDict):
question: str
category: str
answer: str
builder = StateGraph(State)
# A node gets the full state and returns only what it changes:
def classify(state: State) -> dict:
q = state["question"].lower()
return {"category": "billing" if "refund" in q else "general"}
print(classify({"question": "I want a refund", "category": "", "answer": ""}))
# {'category': 'billing'}Remember
- State is declared with a TypedDict (or Pydantic model/dataclass)
- StateGraph(State) creates the builder
- Nodes return partial updates; LangGraph merges them
- By default an update replaces the key's old value