Runtime context: per-run data with context_schema
Runtime context is per-run data, such as a user id, an API client or a model choice, passed to nodes and tools through context_schema so it stays out of the graph's state.
Last updated: 27 Sep, 2026 · LangGraph 1.2
State is the data that flows and changes between nodes. Some things are fixed for a whole run, like who is asking or which database to use. Those do not belong in state; they belong in the run's context.
Declaring a context schema
Describe the run's fixed data as a dataclass and hand it to StateGraph as context_schema.
from dataclasses import dataclass
from langgraph.graph import StateGraph, START, END
from langgraph.runtime import Runtime
@dataclass
class Context: # fixed for the whole run
user: strReading context in a node
A node takes a second argument, runtime, and reads the values off runtime.context. The node never puts them in state.
def greet(state, runtime: Runtime[Context]):
# read per-run data off runtime.context, not off state
return {"greeting": f"Hello, {runtime.context.user}!"}Passing context at run time
Build the graph on the context schema, then pass a context object to invoke with the context= argument.
class State(TypedDict):
greeting: str
b = StateGraph(State, context_schema=Context) # declare the context
b.add_node("greet", greet)
b.add_edge(START, "greet")
b.add_edge("greet", END)print(graph.invoke({"greeting": ""}, context=Context(user="Ada"))["greeting"])Greeting a named user end to end
The whole program in one file.
from dataclasses import dataclass
from typing_extensions import TypedDict
from langgraph.graph import StateGraph, START, END
from langgraph.runtime import Runtime
@dataclass
class Context:
user: str
class State(TypedDict):
greeting: str
def greet(state, runtime: Runtime[Context]):
return {"greeting": f"Hello, {runtime.context.user}!"}
b = StateGraph(State, context_schema=Context)
b.add_node("greet", greet)
b.add_edge(START, "greet")
b.add_edge("greet", END)
graph = b.compile()
print(graph.invoke({"greeting": ""}, context=Context(user="Ada"))["greeting"])What the run used
context_schema=Contexttold the graph what fixed data a run carries.greetreadruntime.context.user; the value never entered state.invoke(..., context=Context(user="Ada"))supplied it for this one run.
State vs context
| State | Context | |
|---|---|---|
| Changes between nodes | Yes | No, fixed for the run |
| A node can write it | Yes, by returning keys | No, it is read-only |
| Saved by the checkpointer | Yes | No |
| Use for | Data the graph builds up | A user id, a client, a model choice |
When to use context
- The caller's identity or tenant, so a tool acts for the right user.
- An API client, database handle or model choice shared by every node.
- Wiring a user id into the store's namespace so memory is per user.
invoke. Put anything that must change or persist in state instead.Related
- Previous: Store: memory across conversations
- Next: Trimming and removing messages
- Reference: Graph API: runtime context
- Add a
tierfield toContextand greet gold users differently. - Read
runtime.contextinside a tool and act for that user. - Try to write the user into state and see why context is the better home for it.
This is what real progress feels like.