Low-level orchestration framework for building stateful, multi-actor applications with LLMs
Graph construction in LangGraph involves defining workflows using StateGraph or Graph classes, along with the Annotation system for type-safe state management. These APIs enable building complex, stateful workflows with nodes, edges, and conditional routing.
High-level graph API with automatic state management through channels. StateGraph provides typed state management where nodes communicate by reading from and writing to shared state channels.
class StateGraph<
StateDefinition,
S = StateType<StateDefinition>,
U = UpdateType<StateDefinition>,
N extends string = typeof START,
InputDefinition = StateDefinition,
OutputDefinition = StateDefinition,
ContextDefinition = StateDefinition,
NodeReturnType = unknown,
InterruptType = unknown,
WriterType = unknown
> {
constructor(
state: AnnotationRoot<StateDefinition> | InteropZodObject,
options?: {
context?: ContextDefinition | AnnotationRoot<ContextDefinition>;
input?: InputDefinition | AnnotationRoot<InputDefinition>;
output?: OutputDefinition | AnnotationRoot<OutputDefinition>;
interrupt?: InterruptType;
writer?: WriterType;
nodes?: N[];
}
);
addNode<K extends string>(
key: K,
action: RunnableLike<S, U>,
options?: StateGraphAddNodeOptions
): StateGraph<StateDefinition, S, U, N | K, InputDefinition, OutputDefinition, ContextDefinition, NodeReturnType>;
addNode<K extends string>(
nodes: Record<K, RunnableLike<S, U>>
): StateGraph<StateDefinition, S, U, N | K, InputDefinition, OutputDefinition, ContextDefinition, NodeReturnType>;
addNode<K extends string>(
nodes: [key: K, action: RunnableLike<S, U>, options?: StateGraphAddNodeOptions][]
): StateGraph<StateDefinition, S, U, N | K, InputDefinition, OutputDefinition, ContextDefinition, NodeReturnType>;
addEdge(
startKey: typeof START | N | N[],
endKey: N | typeof END
): this;
addConditionalEdges(
source: N,
path: RunnableLike<S, string | string[] | Send | Send[]>,
pathMap?: Record<string, N | typeof END> | (N | typeof END)[]
): this;
addConditionalEdges(
options: {
source: N;
path: RunnableLike<S, string | string[] | Send | Send[]>;
pathMap?: Record<string, N | typeof END> | (N | typeof END)[];
}
): this;
addSequence<K extends string>(
nodes: Record<K, RunnableLike<S, U>>
): StateGraph<StateDefinition, S, U, N | K, InputDefinition, OutputDefinition, ContextDefinition, NodeReturnType>;
addSequence<K extends string>(
nodes: [key: K, action: RunnableLike<S, U>, options?: StateGraphAddNodeOptions][]
): StateGraph<StateDefinition, S, U, N | K, InputDefinition, OutputDefinition, ContextDefinition, NodeReturnType>;
setEntryPoint(name: N): this;
setFinishPoint(name: N): this;
compile(options?: {
checkpointer?: BaseCheckpointSaver | boolean;
store?: BaseStore;
cache?: BaseCache;
interruptBefore?: N[] | All;
interruptAfter?: N[] | All;
name?: string;
description?: string;
}): CompiledStateGraph<S, U, N, InputDefinition, OutputDefinition, ContextDefinition, NodeReturnType, InterruptType, WriterType>;
}Lower-level graph class for workflow definition without automatic state management. Provides manual control over node communication and state handling.
class Graph<
N extends string = typeof START | typeof END,
RunInput = any,
RunOutput = any,
NodeSpecType extends NodeSpec<RunInput, RunOutput> = NodeSpec<RunInput, RunOutput>,
ContextDefinition extends StateDefinition = StateDefinition
> {
nodes: Record<N, NodeSpecType>;
edges: Set<[N | typeof START, N | typeof END]>;
branches: Record<string, Record<string, Branch<RunInput, N>>>;
constructor();
addNode<K extends string>(
key: K,
action: RunnableLike<RunInput, RunOutput>,
options?: AddNodeOptions
): Graph<N | K, RunInput, RunOutput>;
addNode<K extends string>(
nodes: Record<K, RunnableLike<RunInput, RunOutput>>
): Graph<N | K, RunInput, RunOutput>;
addNode<K extends string>(
nodes: [key: K, action: RunnableLike<RunInput, RunOutput>, options?: AddNodeOptions][]
): Graph<N | K, RunInput, RunOutput>;
addEdge(
startKey: N | typeof START,
endKey: N | typeof END
): this;
addConditionalEdges(
source: N,
path: RunnableLike<RunInput, string | Send | (string | Send)[]>,
pathMap?: Record<string, N | typeof END> | (N | typeof END)[]
): this;
addConditionalEdges(
options: BranchOptions<RunInput, N>
): this;
setEntryPoint(key: N): this;
setFinishPoint(key: N): this;
compile(options?: {
checkpointer?: BaseCheckpointSaver | false;
interruptBefore?: N[] | All;
interruptAfter?: N[] | All;
name?: string;
}): CompiledGraph<N>;
validate(interrupt?: string[]): void;
}Compiled executable graph from StateGraph. Extends Pregel with state management capabilities.
class CompiledStateGraph<
S,
U,
N extends string = typeof START,
InputDefinition = StateDefinition,
OutputDefinition = StateDefinition,
ContextDefinition = StateDefinition,
NodeReturnType = unknown,
InterruptType = unknown,
WriterType = unknown
> extends CompiledGraph<N, S, U> {
description?: string;
invoke(
input: UpdateType<InputDefinition>,
options?: PregelOptions
): Promise<StateType<OutputDefinition>>;
stream(
input: UpdateType<InputDefinition>,
options?: PregelOptions
): IterableReadableStream;
streamEvents(
input: UpdateType<InputDefinition>,
options: PregelOptions
): IterableReadableStream;
getState(
config: LangGraphRunnableConfig,
options?: GetStateOptions
): Promise<StateSnapshot>;
getStateHistory(
config: LangGraphRunnableConfig,
options?: CheckpointListOptions
): AsyncIterableIterator<StateSnapshot>;
updateState(
config: LangGraphRunnableConfig,
values: UpdateType<InputDefinition> | Command,
asNode?: N
): Promise<RunnableConfig>;
isInterrupted(input: unknown): input is {
[INTERRUPT]: Interrupt<InferInterruptInputType<InterruptType>>[];
};
}Compiled executable graph from Graph class. Provides core execution capabilities.
class CompiledGraph<
N extends string,
State = any,
Update = any,
ContextType extends Record<string, any> = Record<string, any>,
InputType = any,
OutputType = any,
NodeReturnType = unknown,
CommandType = unknown,
StreamCustomType = any
> extends Pregel<...> {
builder: Graph<N, State, Update>;
invoke(
input: InputType,
options?: PregelOptions
): Promise<OutputType>;
stream(
input: InputType,
options?: PregelOptions
): IterableReadableStream;
getGraph(
config?: RunnableConfig & { xray?: boolean | number }
): DrawableGraph;
getGraphAsync(
config?: RunnableConfig & { xray?: boolean | number }
): Promise<DrawableGraph>;
}Factory for creating typed state annotations. The Annotation system provides type-safe state definitions with automatic type inference.
interface AnnotationFunction {
<ValueType>(): LastValue<ValueType>;
<ValueType, UpdateType = ValueType>(
annotation: SingleReducer<ValueType, UpdateType>
): BinaryOperatorAggregate<ValueType, UpdateType>;
Root: <S extends StateDefinition>(
spec: S
) => AnnotationRoot<S>;
}
const Annotation: AnnotationFunction;Usage examples:
// Simple field without reducer (last value wins)
const SimpleAnnotation = Annotation.Root({
count: Annotation<number>
});
// Field with reducer for aggregation
const AnnotationWithReducer = Annotation.Root({
messages: Annotation<BaseMessage[]>({
reducer: (left, right) => left.concat(right),
default: () => []
}),
total: Annotation<number>({
reducer: (a, b) => a + b,
default: () => 0
})
});Root state annotation wrapper providing State/Update/Node type inference.
class AnnotationRoot<StateDefinition extends StateDefinition> {
lc_graph_name: "AnnotationRoot";
spec: StateDefinition;
declare State: StateType<StateDefinition>;
declare Update: UpdateType<StateDefinition>;
declare Node: NodeType<StateDefinition>;
constructor(spec: StateDefinition);
}State reducer function type for combining state updates.
type SingleReducer<ValueType, UpdateType = ValueType> =
| {
reducer: BinaryOperator<ValueType, UpdateType>;
default?: () => ValueType;
}
| {
value: BinaryOperator<ValueType, UpdateType>;
default?: () => ValueType;
}
| null;
type BinaryOperator<ValueType, UpdateType> = (
a: ValueType,
b: UpdateType
) => ValueType;Type definition for message inputs to message-based workflows.
type Messages =
| Array<BaseMessage | BaseMessageLike>
| BaseMessage
| BaseMessageLike;Legacy graph class specialized for message handling. Prefer using StateGraph with MessagesAnnotation for new code.
class MessageGraph extends StateGraph<
BaseMessage[],
BaseMessage[],
Messages
> {
constructor();
}Special constant used with RemoveMessage to remove all messages from state.
const REMOVE_ALL_MESSAGES: "__remove_all__";import { RemoveMessage, REMOVE_ALL_MESSAGES } from "@langchain/langgraph";
// Remove all messages from state
const removeAllMessage = new RemoveMessage({ id: REMOVE_ALL_MESSAGES });
// Use in a node
const clearMessages = (state: any) => {
return {
messages: [new RemoveMessage({ id: REMOVE_ALL_MESSAGES })]
};
};Type utilities for extracting types from state definitions.
interface StateDefinition {
[key: string]: BaseChannel | (() => BaseChannel);
}
type StateType<SD extends StateDefinition> = {
[key in keyof SD]: ExtractValueType<SD[key]>;
};
type UpdateType<SD extends StateDefinition> = {
[key in keyof SD]?: ExtractUpdateType<SD[key]>;
};
type NodeType<SD extends StateDefinition> = RunnableLike<
StateType<SD>,
UpdateType<SD> | Partial<StateType<SD>>
>;Options for adding nodes to graphs.
interface StateGraphAddNodeOptions<Nodes extends string = string> {
retryPolicy?: RetryPolicy;
cachePolicy?: CachePolicy | boolean;
input?: AnnotationRoot<any> | InteropZodObject;
metadata?: Record<string, unknown>;
subgraphs?: Pregel<any, any>[];
ends?: Nodes[];
defer?: boolean;
}
interface AddNodeOptions<Nodes extends string = string> {
metadata?: Record<string, unknown>;
subgraphs?: Pregel<any, any>[];
ends?: Nodes[];
defer?: boolean;
}
interface NodeSpec<RunInput, RunOutput> {
runnable: Runnable<RunInput, RunOutput>;
metadata?: Record<string, unknown>;
subgraphs?: Pregel<any, any>[];
ends?: string[];
defer?: boolean;
}Conditional edge implementation for dynamic routing.
class Branch<
IO,
N extends string,
CallOptions extends LangGraphRunnableConfig = LangGraphRunnableConfig
> {
path: Runnable<IO, BranchPathReturnValue, CallOptions>;
ends?: Record<string, N | typeof END>;
constructor(options: {
path: RunnableLike<IO, BranchPathReturnValue, CallOptions>;
pathMap?: Record<string, N | typeof END> | (N | typeof END)[];
});
run(
writer: (dests: (string | Send)[], config: LangGraphRunnableConfig) => Runnable | void | Promise<void>,
reader?: (config: CallOptions) => IO
): ChannelWrite;
}
type BranchPathReturnValue =
| string
| Send
| (string | Send)[]
| Promise<string | Send | (string | Send)[]>;
interface BranchOptions<IO, N extends string> {
source: N;
path: RunnableLike<IO, BranchPathReturnValue>;
pathMap?: Record<string, N | typeof END> | (N | typeof END)[];
}Reserved node identifiers for graph flow control.
const START: "__start__";
const END: "__end__";import { StateGraph, Annotation, START, END } from "@langchain/langgraph";
// Define state using Annotation
const StateAnnotation = Annotation.Root({
messages: Annotation<string[]>({
reducer: (current, update) => [...current, ...update],
default: () => []
}),
count: Annotation<number>({
reducer: (_, update) => update,
default: () => 0
})
});
// Create nodes
const processNode = (state: typeof StateAnnotation.State) => {
return {
messages: [`Processed ${state.count} items`],
count: state.count + 1
};
};
// Build graph
const graph = new StateGraph(StateAnnotation)
.addNode("process", processNode)
.addEdge(START, "process")
.addEdge("process", END);
// Compile and execute
const app = graph.compile();
const result = await app.invoke({
messages: ["Hello"],
count: 0
});
// { messages: ["Hello", "Processed 0 items"], count: 1 }import { StateGraph, Annotation, START, END } from "@langchain/langgraph";
const StateAnnotation = Annotation.Root({
value: Annotation<number>
});
const graph = new StateGraph(StateAnnotation)
.addNode("check", (state) => state)
.addNode("positive", (state) => ({ value: state.value * 2 }))
.addNode("negative", (state) => ({ value: state.value * -1 }))
.addEdge(START, "check")
.addConditionalEdges(
"check",
(state) => (state.value > 0 ? "positive" : "negative"),
{
positive: "positive",
negative: "negative"
}
)
.addEdge("positive", END)
.addEdge("negative", END);
const app = graph.compile();
await app.invoke({ value: 5 }); // { value: 10 }
await app.invoke({ value: -3 }); // { value: 3 }import { StateGraph, Annotation } from "@langchain/langgraph";
// Define different state schemas for input, internal state, and output
const InternalState = Annotation.Root({
messages: Annotation<string[]>({
reducer: (a, b) => a.concat(b),
default: () => []
}),
internalCounter: Annotation<number>
});
const InputState = Annotation.Root({
messages: Annotation<string[]>
});
const OutputState = Annotation.Root({
messages: Annotation<string[]>
});
// Create graph with different input/output schemas
const graph = new StateGraph(InternalState, {
input: InputState,
output: OutputState
})
.addNode("process", (state) => ({
messages: ["processed"],
internalCounter: (state.internalCounter || 0) + 1
}))
.addEdge(START, "process")
.addEdge("process", END)
.compile();
// Input only requires messages
await graph.invoke({ messages: ["hello"] });
// Output only includes messages (internalCounter is filtered)import { StateGraph, Annotation, START, END } from "@langchain/langgraph";
const State = Annotation.Root({
value: Annotation<number>
});
// Add multiple nodes in sequence automatically
const graph = new StateGraph(State)
.addSequence([
["step1", (s) => ({ value: s.value + 1 })],
["step2", (s) => ({ value: s.value * 2 })],
["step3", (s) => ({ value: s.value + 10 })]
])
.addEdge(START, "step1")
.addEdge("step3", END)
.compile();
await graph.invoke({ value: 5 });
// Executes: ((5 + 1) * 2) + 10 = 22import { StateGraph } from "@langchain/langgraph";
import { z } from "zod";
// Use Zod schemas for state validation
const StateSchema = z.object({
count: z.number().default(0),
messages: z.array(z.string()).default([])
});
const graph = new StateGraph(StateSchema)
.addNode("increment", (state) => ({
count: state.count + 1,
messages: state.messages.concat(["incremented"])
}))
.addEdge(START, "increment")
.addEdge("increment", END)
.compile();
// Input is validated against schema
await graph.invoke({ count: 5 });
// { count: 6, messages: ["incremented"] }