Runnables API Reference

Purpose and Scope

Runnables are LangChain's common execution interface for components such as prompts, chat models, retrievers, chains, parsers, and custom callables. The API matters because it lets application code treat those pieces uniformly: a prompt-model-parser pipeline can be invoked, streamed, batched, traced, configured, inspected as a graph, wrapped with fallbacks, or embedded in evaluation workflows without every component inventing its own lifecycle. Official LangSmith guidance relies on that contract by passing a composed runnable directly to evaluate() or aevaluate(), where the runnable's input keys must match dataset example inputs.

This page is an API reference map rather than a tutorial. It identifies the source modules that define the runnable contract and explains how the surrounding helpers fit together when you build production chains. Use it when you need to decide whether a behavior belongs in the core runnable, in RunnableConfig, in configurable alternatives, in graph visualization, or in message-history wrapping. Sources: libs/core/langchain_core/runnables/base.py, libs/core/langchain_core/runnables/config.py, libs/core/langchain_core/runnables/configurable.py, libs/core/langchain_core/runnables/graph.py, libs/core/langchain_core/runnables/history.py

Relevant Source Files

  • libs/core/langchain_core/runnables/base.py defines the central runnable abstractions and composition surface, including the core invocation methods and wrapper-style APIs such as bindings and fallbacks.
  • libs/core/langchain_core/runnables/config.py defines RunnableConfig, config keys, config merging and propagation helpers, callback-manager integration, executor selection, and concurrency-related utilities.
  • libs/core/langchain_core/runnables/configurable.py defines dynamically configurable runnable wrappers such as DynamicRunnable, and delegates schema, graph, and invocation behavior after selecting the configured implementation.
  • libs/core/langchain_core/runnables/graph.py defines the graph data structures used to inspect runnable pipelines, including Graph, Node, Edge, Branch, LabelsDict, CurveStyle, and NodeStyles.
  • libs/core/langchain_core/runnables/history.py defines RunnableWithMessageHistory, which wraps another runnable and manages chat message history through config-provided session or history-factory fields.

Core Runnable Contract

The runnable contract is centered on a small expectation: callers provide an input value and optional runtime configuration, and the runnable produces an output value through a standardized execution method. In day-to-day code, that surface is what allows a chain such as prompt, model, output parser to be composed with the pipe operator and later passed as one object to an evaluator, server, or another runnable. base.py is the home for that contract and for the higher-level wrappers that preserve the same interface while adding behavior. Sources: libs/core/langchain_core/runnables/base.py

Because all runnables share the same conceptual lifecycle, cross-cutting features can be implemented once and applied broadly. A model call, a retriever call, and a custom lambda can all accept config, participate in tracing callbacks, expose schemas, and be used inside batch or streaming flows when their implementation supports those modes. That is why LangChain examples can compose heterogeneous parts and still treat the result as a single runnable. The practical rule is to keep business logic inside runnable implementations or compositions, and keep per-call runtime choices in the config object instead of baking them into global state.

The same contract supports both synchronous and asynchronous application architectures. Implementations typically expose sync and async invocation families, plus batch and stream variants when the component can benefit from concurrency or incremental output. Higher-level orchestration code should prefer the runnable methods rather than reaching into provider-specific methods, because the runnable layer is where tracing, tags, metadata, config propagation, fallbacks, and wrappers remain consistent. That consistency is especially important when a chain moves from local experiments into LangSmith evaluation or deployment.

RunnableConfig Reference

RunnableConfig is a TypedDict with total=False, which is an intentional design choice rather than an omission. Partial configs can be created independently and then merged, and parent runnables can propagate configuration to child runnables through contextual execution without forcing every function to manually thread the same argument. The source comments describe this with tags: a parent call can set one tag, and a child can add another after config merging instead of replacing the parent configuration. Sources: libs/core/langchain_core/runnables/config.py

The supported config keys are explicit. tags is a list of strings used to label this call and sub-calls. metadata is a string-keyed dictionary whose values should be JSON-serializable. callbacks carries callback handlers or callback managers to receive lifecycle events. run_name names the traced run, while run_id can supply a specific UUID. max_concurrency limits parallel calls, recursion_limit bounds recursive runnable execution and defaults to 25 when not provided, and configurable contains runtime values for fields or alternatives made configurable by runnable APIs.

A useful mental model is that RunnableConfig is for invocation context, not for component construction. Tags, metadata, callbacks, and run identity describe the current call. Concurrency and recursion govern runtime behavior. The configurable dictionary is the bridge to dynamic configuration, where a runnable has already declared which attributes may vary at call time. The module also distinguishes copyable keys, such as tags and metadata, from the complete config key set, and excludes sensitive configurable metadata such as api_key from tracing metadata. Sources: libs/core/langchain_core/runnables/config.py

Configurable Runnables and Alternatives

Configurable runnables let a chain expose safe runtime switches without rewriting the chain itself. DynamicRunnable is the serializable wrapper used after a runnable is made configurable through methods such as configurable_fields or configurable_alternatives. It stores a default runnable and optional config, reports itself as LangChain-serializable, and uses the namespace ['langchain', 'schema', 'runnable']. The wrapper delegates InputType, OutputType, input schema, output schema, and graph inspection to the prepared runnable selected for the current configuration. Sources: libs/core/langchain_core/runnables/configurable.py

The key method is prepare(config). It repeatedly unwraps dynamic runnable layers, merges wrapper config with call config, and returns the concrete runnable plus the effective RunnableConfig. This matters when multiple configuration layers are nested: a chain may define a default model, a configurable temperature, and an alternative provider, while a request supplies only the fields that should change. The wrapper also implements with_config, creating a new configured instance by merging an explicit config dictionary with keyword arguments through ensure_config and merge_configs.

Developers should use configurable fields when the runnable implementation remains the same but selected attributes vary, such as a model parameter exposed to callers. Use configurable alternatives when the runtime choice changes which runnable is used, such as swapping between model providers or retriever strategies under a stable interface. In both cases, the downstream caller still invokes one runnable object. That lets products expose configuration knobs in a UI, API request, or experiment runner without forcing consumers to understand the internal chain wiring.

Graph Inspection and Rendering

Runnable graphs make composition visible. graph.py defines the low-level structures used when a runnable exposes its execution shape: Node records an identifier, name, underlying runnable or schema data, and optional metadata; Edge records source and target node IDs, optional edge data, and whether the edge is conditional; Branch represents conditional paths with a callable condition and optional branch end nodes. These types give graph renderers and inspection tools a stable representation that is separate from any one runnable implementation. Sources: libs/core/langchain_core/runnables/graph.py

The graph module also contains presentation-oriented types. LabelsDict stores labels for nodes and edges. CurveStyle enumerates Mermaid curve styles such as basis, linear, step, and related variants. NodeStyles represents hexadecimal color choices for node categories such as default, first, and last nodes. The presence of these types shows that graph inspection is not only a debugging data structure; it is also intended to produce readable diagrams for chains where understanding the flow is easier visually than by reading nested Python expressions.

Use graph inspection when reviewing non-trivial runnable composition, documenting a reusable chain, or debugging conditional paths. A graph can reveal where a sequence begins and ends, which nodes are runnable steps versus schemas, and which transitions are conditional. It is also a safer boundary for tooling: renderers can consume the graph structures instead of introspecting arbitrary implementation details. For dynamically configurable runnables, graph inspection first prepares the selected runnable for the supplied config, so the displayed graph can reflect the runtime choice rather than only the default.

Fallbacks and Resilient Execution

Fallbacks belong to the runnable wrapper family because they preserve the same external interface while changing error-handling behavior. The core idea is to declare one or more backup runnables that can be tried when the primary runnable fails under configured conditions. Since the fallback chain remains a runnable, callers can still invoke, stream, trace, configure, and compose it like any other component. This design is preferable to scattering try-except blocks around application code, because resilience stays attached to the component boundary where failures occur. Sources: libs/core/langchain_core/runnables/base.py, libs/core/langchain_core/runnables/config.py

When using fallbacks, keep inputs and outputs compatible across the primary and backup implementations. If a primary chat model returns an AI message but a fallback returns a raw string, later steps in the chain may fail even though the fallback itself succeeded. Also consider config propagation: tags, metadata, callbacks, run names, and concurrency settings should still describe the overall call and sub-calls. That makes traces and evaluations easier to interpret because the failure path is visible as part of the same runnable execution tree rather than an unrelated side effect.

Message History Wrapper Reference

RunnableWithMessageHistory wraps another runnable and manages chat message history for it. A chat message history is a sequence of messages representing a conversation, and the wrapper is responsible for reading prior messages before invocation and updating the history afterward. By default, the wrapped runnable is expected to receive a config value under configurable.session_id, and invocation looks like with_history.invoke(..., config={'configurable': {'session_id': 'bar'}}). Sources: libs/core/langchain_core/runnables/history.py

The wrapper supports customization through history_factory_config, a list of ConfigurableFieldSpec objects that describe the configuration parameters required by the history factory. This is important for production applications because session lookup may need more than one value, such as user ID, conversation ID, tenant, region, or storage namespace. The source documentation uses an in-memory history implementation for experimentation, but it explicitly recommends persistent implementations such as Redis-backed chat history for production use cases. Sources: libs/core/langchain_core/runnables/history.py

The wrapper's contract is intentionally broad about input and output shapes. It imports base message types such as BaseMessage, HumanMessage, and AIMessage, accepts message sequences or dictionaries containing messages, and uses runnable helpers such as RunnableLambda and RunnablePassthrough to adapt the wrapped runnable. The practical API guidance is to make the message-bearing input and output keys explicit in your chain design, then configure the wrapper so it knows where to read new user messages and where to append generated responses.

Compact API Map

AreaPublic names and conceptsSource
Runnable executionRunnable, serializable runnables, invocation, async invocation, batching, streaming, composition, bindings, fallbackslibs/core/langchain_core/runnables/base.py
Runtime configRunnableConfig, CONFIG_KEYS, COPIABLE_KEYS, tags, metadata, callbacks, run_name, max_concurrency, recursion_limit, configurable, run_idlibs/core/langchain_core/runnables/config.py
Dynamic configurationDynamicRunnable, configurable_fields, configurable_alternatives, prepare, _prepare, with_config, schema and graph delegationlibs/core/langchain_core/runnables/configurable.py
GraphsGraph, Node, Edge, Branch, LabelsDict, CurveStyle, NodeStyles, UUID helpers, conditional edgeslibs/core/langchain_core/runnables/graph.py
Chat historyRunnableWithMessageHistory, MessagesOrDictWithMessages, GetSessionHistoryCallable, history_factory_config, session_id configlibs/core/langchain_core/runnables/history.py

Usage Pattern

chain = prompt | model | parser
result = chain.invoke({'text': 'hello'}, config={'tags': ['demo'], 'metadata': {'component': 'toxicity-check'}})

A typical runnable flow starts by building a chain from composable components, then invoking it with a plain input object and a RunnableConfig. During execution, the config is normalized and propagated to child runnables, callback managers receive lifecycle events, and any configured concurrency or recursion limits influence nested calls. If the runnable has dynamic fields or alternatives, it is prepared against the current config before schema, graph, or invocation behavior is delegated to the selected implementation. If the runnable is wrapped with message history, it also resolves the configured history before and after the inner call.

For next steps, inspect RunnableConfig first when behavior changes per request, use configurable runnables when behavior changes by declared runtime knobs, call graph inspection when you need to explain a chain, and wrap with RunnableWithMessageHistory when a chat application must persist conversation state. If you are evaluating chains in LangSmith, keep the runnable input schema aligned with dataset example keys so evaluate() and aevaluate() can pass examples directly into the chain.