LangChain/Advanced
Advanced14 min

ToolRuntime: Choosing State, Store, and Context

ToolRuntime bundles state, store, context, and streaming into a single typed parameter for tools. This article is about when to use it, which data goes where, and what breaks in production when you choose wrong.

Quick Reference

  • from langchain.tools import ToolRuntime # or from langgraph.prebuilt import ToolRuntime
  • ToolRuntime(Generic[ContextT, StateT]) — two type params; StateT defaults to dict
  • runtime.context: immutable per-invocation config (user_id, tenant, flags)
  • runtime.state: mutable current-run graph state | runtime.store: cross-session persistence
  • runtime.stream_writer: emit custom events | runtime.tool_call_id: correlate invocations
  • InjectedState / InjectedStore / InjectedConfig are NOT deprecated — use them for single-field access
  • Always include messages=[ToolMessage(...)] in Command(update={...}) — omitting it stalls the graph

Should You Use ToolRuntime?

ToolRuntime consolidates state, store, context, config, and streaming into a single typed parameter. It does NOT replace InjectedState, InjectedStore, or InjectedConfig — those patterns still work and are sometimes simpler. ToolRuntime is a convenience consolidation. Use it when a tool needs two or more runtime services simultaneously; use individual annotations when a tool only needs one.

InjectedState / InjectedStore / InjectedConfig are NOT deprecated

A LangChain contributor confirmed (forum thread, 2025): these are complementary patterns. ToolRuntime is the preferred consolidation when a tool needs multiple runtime services, but the individual annotations remain valid and are sometimes clearer for single-field access.

SituationUseWhy
Tool needs state onlyAnnotated[dict, InjectedState]One annotation, no generic needed, intent is clear
Tool needs store onlyAnnotated[BaseStore, InjectedStore]Same — simpler than ToolRuntime for a single service
Tool needs state + store + contextToolRuntime[MyContext, MyState]One parameter instead of three separate annotations
Tool needs streaming onlyget_stream_writer() from langgraph.configNo ToolRuntime overhead for a single utility
Building with create_agent()ToolRuntimecreate_agent wires context_schema injection; ToolRuntime is the natural fit
Gradual migrationMix bothMigrate tool-by-tool; both patterns work in the same ToolNode