langchain.js
    Preparing search index...

    Type Alias GraphNode<Schema, Context, Nodes>

    GraphNode: IsGraphNodeTypeBag<Schema> extends true
        ? (
            state: ExtractBagInput<Schema, unknown>,
            config: LangGraphRunnableConfig<
                ExtractBagContext<Schema, Record<string, unknown>>,
            >,
        ) => GraphNodeReturnValue<
            ExtractBagOutput<Schema, Partial<ExtractBagInput<Schema, unknown>>>,
            ExtractBagNodes<Schema, string>,
        >
        : (
            state: ExtractStateType<Schema>,
            config: LangGraphRunnableConfig<Context>,
        ) => GraphNodeReturnValue<ExtractUpdateType<Schema>, Nodes>

    Strongly-typed utility for authoring graph nodes outside of the StateGraph builder, supporting inference for both state (from Schema) and config context (from Context type).

    This type enables you to define graph node functions with full type safety—both for the evolving state and for additional context that may be passed in at runtime. Typing the context parameter allows for better code organization and precise editor support.

    Works with StateSchema, AnnotationRoot, and Zod object schemas for state, and with a user-defined object shape for context.

    Supports two patterns:

    1. Single schema usage - Single schema for both input and output: GraphNode<Schema, Context, Nodes>

    2. Type bag pattern - Separate schemas for input, output, context: GraphNode<{ InputSchema; OutputSchema; ContextSchema; Nodes }>

    Type Parameters

    • Schema

      The state schema type (StateSchema, AnnotationRoot, InteropZodObject) OR a type bag

    • Context extends Record<string, any> = Record<string, any>

      The type of the context passed into this node (default: Record<string, unknown>)

    • Nodes extends string = string

      An optional union of valid node names for Command.goto, used for type-safe routing (default: string)

    import { StateSchema, GraphNode } from "@langchain/langgraph";
    import { z } from "zod/v4";

    const AgentState = new StateSchema({
    messages: MessagesValue,
    step: z.number().default(0),
    });

    // Context shape for custom node logic (optional)
    type MyContext = { userId: string };

    // Node receiving state and config
    const processNode: GraphNode<typeof AgentState, MyContext> = (state, config) => {
    const userId = config.configurable?.userId; // type-safe context access
    return { step: state.step + 1 };
    };

    // Node with type-safe graph routing
    const routerNode: GraphNode<typeof AgentState, MyContext, "agent" | "tool"> = (state, config) => {
    if (state.needsTool) {
    return new Command({ goto: "tool", update: { step: state.step + 1 } });
    }
    return new Command({ goto: "agent" });
    };

    // Use in graph
    const graph = new StateGraph(AgentState)
    .addNode("process", processNode)
    .addNode("router", routerNode)
    .compile();
    const InputSchema = new StateSchema({
    messages: z.array(z.string()),
    query: z.string(),
    });

    const OutputSchema = new StateSchema({
    answer: z.string(),
    });

    const ContextSchema = z.object({ userId: z.string() });

    const node: GraphNode<{
    InputSchema: typeof InputSchema;
    OutputSchema: typeof OutputSchema;
    ContextSchema: typeof ContextSchema;
    Nodes: "agent" | "tool";
    }> = (state, config) => {
    // state is { messages: string[]; query: string }
    // config.configurable is { userId: string } | undefined
    return { answer: `Response to: ${state.query}` };
    };