Documentation Index
Fetch the complete documentation index at: https://docs.langchain.com/llms.txt
Use this file to discover all available pages before exploring further.
LangGraph provides two different APIs to build agent workflows: the Graph API and the Functional API. Both APIs share the same underlying runtime and can be used together in the same application, but they are designed for different use cases and development preferences.
This guide will help you understand when to use each API based on your specific requirements.
Quick decision guide
Use the Graph API when you need:
- Complex workflow visualization for debugging and documentation
- Explicit state management with shared data across multiple nodes
- Conditional branching with multiple decision points
- Parallel execution paths that need to merge later
- Team collaboration where visual representation aids understanding
Use the Functional API when you want:
- Minimal code changes to existing procedural code
- Standard control flow (if/else, loops, function calls)
- Function-scoped state without explicit state management
- Rapid prototyping with less boilerplate
- Linear workflows with simple branching logic
Detailed comparison
When to use the Graph API
The Graph API uses a declarative approach where you define nodes, edges, and shared state to create a visual graph structure.
1. Complex decision trees and branching logic
When your workflow has multiple decision points that depend on various conditions, the Graph API makes these branches explicit and easy to visualize.
import * as z from "zod";
import {
StateGraph,
StateSchema,
MessagesValue,
START,
END,
type GraphNode,
type ConditionalEdgeRouter,
} from "@langchain/langgraph";
// Graph API: Clear visualization of decision paths
const AgentState = new StateSchema({
messages: MessagesValue,
currentTool: z.string(),
retryCount: z.number().default(0),
});
const shouldContinue: ConditionalEdgeRouter<typeof AgentState> = (state) => {
if (state.retryCount > 3) {
return END;
} else if (state.currentTool === "search") {
return "processSearch";
} else {
return "callLlm";
}
};
const workflow = new StateGraph(AgentState)
.addNode("callLlm", callLlmNode)
.addNode("processSearch", searchNode)
.addConditionalEdges("callLlm", shouldContinue);
2. State management across multiple components
When you need to share and coordinate state between different parts of your workflow, the Graph API’s explicit state management is beneficial.
import * as z from "zod";
import { StateSchema, type GraphNode } from "@langchain/langgraph";
// Multiple nodes can access and modify shared state
const WorkflowState = new StateSchema({
userInput: z.string(),
searchResults: z.array(z.string()).default([]),
generatedResponse: z.string().optional(),
validationStatus: z.string().optional(),
});
const searchNode: GraphNode<typeof WorkflowState> = async (state) => {
// Access shared state
const results = await search(state.userInput);
return { searchResults: results };
};
const validationNode: GraphNode<typeof WorkflowState> = async (state) => {
// Access results from previous node
const isValid = await validate(state.generatedResponse);
return { validationStatus: isValid ? "valid" : "invalid" };
};
3. Parallel processing with synchronization
When you need to run multiple operations in parallel and then combine their results, the Graph API handles this naturally.
import { START } from "@langchain/langgraph";
// Parallel processing of multiple data sources
workflow
.addNode("fetchNews", fetchNews)
.addNode("fetchWeather", fetchWeather)
.addNode("fetchStocks", fetchStocks)
.addNode("combineData", combineAllData)
// All fetch operations run in parallel
.addEdge(START, "fetchNews")
.addEdge(START, "fetchWeather")
.addEdge(START, "fetchStocks")
// Combine waits for all parallel operations to complete
.addEdge("fetchNews", "combineData")
.addEdge("fetchWeather", "combineData")
.addEdge("fetchStocks", "combineData");
4. Team development and documentation
The visual nature of the Graph API makes it easier for teams to understand, document, and maintain complex workflows.
// Clear separation of concerns - each team member can work on different nodes
workflow
.addNode("dataIngestion", dataTeamFunction)
.addNode("mlProcessing", mlTeamFunction)
.addNode("businessLogic", productTeamFunction)
.addNode("outputFormatting", frontendTeamFunction);
When to use the Functional API
The Functional API uses an imperative approach that integrates LangGraph features into standard procedural code.
1. Existing procedural code
When you have existing code that uses standard control flow and want to add LangGraph features with minimal refactoring.
import { task, entrypoint } from "@langchain/langgraph";
// Functional API: Minimal changes to existing code
const processUserInput = task(
"processUserInput",
async (userInput: string) => {
// Existing function with minimal changes
return { processed: userInput.toLowerCase().trim() };
}
);
const workflow = entrypoint(
{ checkpointer },
async (userInput: string) => {
// Standard control flow
const processed = await processUserInput(userInput);
let response: string;
if (processed.processed.includes("urgent")) {
response = await handleUrgentRequest(processed);
} else {
response = await handleNormalRequest(processed);
}
return response;
}
);
2. Linear workflows with simple logic
When your workflow is primarily sequential with straightforward conditional logic.
import { entrypoint, interrupt } from "@langchain/langgraph";
const essayWorkflow = entrypoint(
{ checkpointer },
async (topic: string) => {
// Linear flow with simple branching
let outline = await createOutline(topic);
if (outline.points.length < 3) {
outline = await expandOutline(outline);
}
const draft = await writeDraft(outline);
// Human review checkpoint
const feedback = interrupt({ draft, action: "Please review" });
let finalEssay: string;
if (feedback === "approve") {
finalEssay = draft;
} else {
finalEssay = await reviseEssay(draft, feedback);
}
return { essay: finalEssay };
}
);
3. Rapid prototyping
When you want to quickly test ideas without the overhead of defining state schemas and graph structures.
import { entrypoint } from "@langchain/langgraph";
const quickPrototype = entrypoint(
{ checkpointer },
async (data: Record<string, unknown>) => {
// Fast iteration - no state schema needed
const step1Result = await processStep1(data);
const step2Result = await processStep2(step1Result);
return { finalResult: step2Result };
}
);
4. Function-scoped state management
When your state is naturally scoped to individual functions and doesn’t need to be shared broadly.
import { task, entrypoint } from "@langchain/langgraph";
const analyzeDocument = task("analyzeDocument", async (document: string) => {
// Local state management within function
const sections = extractSections(document);
const summaries = await Promise.all(sections.map(summarize));
const keyPoints = extractKeyPoints(summaries);
return {
sections: sections.length,
summaries,
keyPoints,
};
});
const documentProcessor = entrypoint(
{ checkpointer },
async (document: string) => {
const analysis = await analyzeDocument(document);
// State is passed between functions as needed
return await generateReport(analysis);
}
);
Combining both APIs
You can use both APIs together in the same application. This is useful when different parts of your system have different requirements.
import * as z from "zod";
import {
StateGraph,
StateSchema,
entrypoint,
type GraphNode,
} from "@langchain/langgraph";
// Define state for complex multi-agent coordination
const CoordinationState = new StateSchema({
rawData: z.record(z.string(), z.unknown()),
processedData: z.record(z.string(), z.unknown()).optional(),
});
// Simple data processing using Functional API
const dataProcessor = entrypoint({}, async (rawData: Record<string, unknown>) => {
const cleaned = await cleanData(rawData);
const transformed = await transformData(cleaned);
return transformed;
});
// Use the functional API result in the graph
const orchestratorNode: GraphNode<typeof CoordinationState> = async (state) => {
const processedData = await dataProcessor.invoke(state.rawData);
return { processedData };
};
// Complex multi-agent coordination using Graph API
const coordinationGraph = new StateGraph(CoordinationState)
.addNode("orchestrator", orchestratorNode)
.addNode("agentA", agentANode)
.addNode("agentB", agentBNode);
Migration between APIs
From Functional to Graph API
When your functional workflow grows complex, you can migrate to the Graph API:
import * as z from "zod";
import { entrypoint } from "@langchain/langgraph";
// Before: Functional API
const complexWorkflow = entrypoint(
{ checkpointer },
async (inputData: Record<string, unknown>) => {
const step1 = await processStep1(inputData);
let result: unknown;
if (step1.needsAnalysis) {
const analysis = await analyzeData(step1);
if (analysis.confidence > 0.8) {
result = await highConfidencePath(analysis);
} else {
result = await lowConfidencePath(analysis);
}
} else {
result = await simplePath(step1);
}
return result;
}
);
// After: Graph API
import {
StateGraph,
StateSchema,
type GraphNode,
type ConditionalEdgeRouter,
} from "@langchain/langgraph";
const WorkflowState = new StateSchema({
inputData: z.record(z.string(), z.unknown()),
step1Result: z.record(z.string(), z.unknown()).optional(),
analysis: z.record(z.string(), z.unknown()).optional(),
finalResult: z.unknown().optional(),
});
const shouldAnalyze: ConditionalEdgeRouter<typeof WorkflowState> = (state) => {
return state.step1Result?.needsAnalysis ? "analyze" : "simplePath";
};
const confidenceCheck: ConditionalEdgeRouter<typeof WorkflowState> = (state) => {
return (state.analysis?.confidence as number) > 0.8
? "highConfidence"
: "lowConfidence";
};
const workflow = new StateGraph(WorkflowState)
.addNode("step1", processStep1Node)
.addConditionalEdges("step1", shouldAnalyze)
.addNode("analyze", analyzeDataNode)
.addConditionalEdges("analyze", confidenceCheck);
// ... add remaining nodes and edges
From Graph to Functional API
When your graph becomes overly complex for simple linear processes:
import { z } from "zod/v4";
import { StateGraph, StateSchema, entrypoint } from "@langchain/langgraph";
// Before: Over-engineered Graph API
const SimpleState = new StateSchema({
input: z.string(),
step1: z.string().optional(),
step2: z.string().optional(),
result: z.string().optional(),
});
// After: Simplified Functional API
const simpleWorkflow = entrypoint(
{ checkpointer },
async (inputData: string) => {
const step1 = await processStep1(inputData);
const step2 = await processStep2(step1);
return await finalizeResult(step2);
}
);
Summary
Choose the Graph API when you need explicit control over workflow structure, complex branching, parallel processing, or team collaboration benefits.
Choose the Functional API when you want to add LangGraph features to existing code with minimal changes, have simple linear workflows, or need rapid prototyping capabilities.
Both APIs provide the same core LangGraph features (persistence, streaming, human-in-the-loop, memory) but package them in different paradigms to suit different development styles and use cases.