LangChain vs Vercel AI SDK: Which to Pick in 2026
By Ergini, Software & AI Developer in Pristina, Kosovo
TL;DR
Use Vercel AI SDK for the app endpoints. Use LangChain - sparingly - for heavy orchestration. This is when each one earns its bundle size, what each does well, and the hybrid pattern that ships in real Next.js apps.
Direct verdict: which one to pick in 2026
For most TypeScript apps shipping AI features in 2026, use the Vercel AI SDK for your application endpoints, useChat for the UI, generateObject for structured output, and streamText for everything else. It is small, TypeScript-native, ships with first-class streaming, and the provider story covers OpenAI, Anthropic, Google, xAI, Mistral, and a long tail through a single interface. For 80% of what people call "an AI feature" in a Next.js app, the AI SDK is the right answer and LangChain is overkill.
Reach for LangChain JS - sparingly - when you genuinely need its document loader and retriever ecosystem, or when you need LangGraph for stateful, multi-step orchestration with checkpointing and human-in-the-loop pauses. The hybrid pattern - AI SDK at the edges, LangGraph in a separate worker for heavy graphs - is what I ship for serious projects. Anyone telling you to pick exactly one for everything is selling you a worldview, not an architecture.
2026 landscape: what changed in the last 12 months
The framework conversation in early 2025 was binary: LangChain or roll your own. By mid-2026 the picture is sharper. The Vercel AI SDK crossed its 6.x line, matured the agent and tool primitives, added first-class support for multimodal input and reasoning models, and cleaned up the provider abstraction so swapping models is genuinely one line of code. The bundle is smaller than it was in 2024 because the team has been aggressive about tree-shaking and code splitting.
LangChain went the other direction and got leaner by splitting. The original mega-package is largely deprecated. langchain-core is small and focused, the chain-style APIs have been replaced by LCEL composition, and the real center of gravity moved to LangGraph for stateful orchestration. The community story now is "use langchain-core for primitives, langgraph for graphs, and only pull in the loader or retriever you need." That is a healthier story than 2024, but it requires discipline most teams do not apply, which is why LangChain still has its bundle-bloat reputation.
The third thing that changed is the rise of MCP and tool calling as the dominant interface for agents. Both frameworks support tool calling well in 2026, but the AI SDK's tool API is closer to the underlying provider semantics, while LangChain's tool API adds an abstraction layer that helps with portability and hurts when you want to use a provider-specific feature.
Comparison table: Vercel AI SDK vs LangChain JS
This is the cheat sheet I use when scoping a new project. None of these are absolute - your situation may flip a row - but the shape holds across the dozens of TypeScript AI projects I have shipped or reviewed in the last 18 months.
| Dimension | Vercel AI SDK 6.x | LangChain JS (core + langgraph) |
|---|---|---|
| Bundle size (typical route) | ~45 to 60 KB gzipped | ~120 KB (lean) to 350 KB (kitchen sink) |
| Streaming UI | First-class, useChat hook | Works, more glue code |
| Tool calling | Zod schemas, parallel calls, typed | Zod schemas, parallel calls, abstracted |
| RAG | You bring the retriever | Massive loader and retriever ecosystem |
| Agents | Lightweight loops, you control flow | LangGraph: real graph runtime, checkpoints |
| Observability | OTel, Langfuse, Helicone (via fetch) | LangSmith native, others via callbacks |
| TypeScript ergonomics | Excellent, type inference everywhere | Good, more generics to think about |
| Provider coverage | 20+ providers, unified API | 50+ providers, deeper integrations |
| API stability | Stable since 5.x, careful breaking changes | Faster churn, deprecations every few months |
| Cold start on Vercel | Fast, minimal impact | Noticeable on first invocation |
The two rows that matter most for production are bundle size and cold start. A single Next.js API route running on Vercel Functions with the kitchen-sink LangChain import can add 200 to 400 ms to cold start latency that the AI SDK simply does not. For high-traffic consumer apps that is the whole user experience difference.
What Vercel AI SDK does well
The AI SDK does four things better than any alternative in the TypeScript ecosystem right now: streaming UI, structured output, provider abstraction, and bundle discipline. Everything else it does is competent; these four are where it pulls ahead.
Streaming UI with useChat. The useChat React hook is the cleanest abstraction over server-sent events I have used. It handles message state, optimistic updates, tool call rendering, and error retries with one hook and one API route. A working chat UI with tool calls is roughly 40 lines of code total.
// app/api/chat/route.ts
import { streamText, tool } from "ai";
import { openai } from "@ai-sdk/openai";
import { z } from "zod";
export const maxDuration = 30;
export async function POST(req: Request) {
const { messages } = await req.json();
const result = streamText({
model: openai("gpt-5"),
messages,
tools: {
getWeather: tool({
description: "Get the current weather for a city",
parameters: z.object({ city: z.string() }),
execute: async ({ city }) => {
const data = await fetch(`https://api.weather/${city}`).then(r => r.json());
return { tempC: data.temp, conditions: data.summary };
},
}),
},
maxSteps: 5,
});
return result.toDataStreamResponse();
}generateObject for typed structured output. The Zod schema becomes the return type, refusals throw a typed error, and retries happen automatically on schema validation failures. This is what I cover in detail in the OpenAI structured outputs deep dive, but the AI SDK's wrapper is the cleanest path.
Multimodal input. Images, PDFs, and audio are all attachments on a message - same API across providers that support them. No special endpoints, no manual base64 wrangling.
The provider abstraction. Swapping from GPT-5 to Claude Opus to Gemini is a one-line change that propagates through tool calling, streaming, and structured output. Combined with the Vercel AI Gateway you get failover and observability without any code changes.
What LangChain does well
LangChain's strengths in 2026 are concentrated in three areas: the loader and retriever ecosystem, LCEL composition for complex retrieval pipelines, and LangGraph for stateful agents. If your project lives in one of those areas, LangChain earns its bundle size.
Document loaders and retrievers. This is the moat nothing else has. Maintained loaders for PDFs, Notion, Confluence, GitHub, Google Drive, Slack, web pages, sitemaps, S3, and dozens more. Retrievers for every vector database with sensible defaults. For an ingestion pipeline, importing one or two LangChain loaders into a background job is unambiguously the right call.
LCEL composition. The pipe operator and Runnable interface let you build complex retrieval pipelines as composable units. For multi-step RAG with reranking, query rewriting, and guarded generation, LCEL stays readable where hand-written equivalent code starts to sprawl.
LangGraph for stateful agents. This is the real prize. LangGraph is a graph runtime with first-class support for cycles, checkpointing, human-in-the-loop pauses, time travel, and durable state. It is what you would build if you needed a real agent platform and had six months. Sample shape:
// LangGraph sketch: a research agent with reflection
import { StateGraph, Annotation, MemorySaver } from "@langchain/langgraph";
import { ChatOpenAI } from "@langchain/openai";
const State = Annotation.Root({
question: Annotation<string>(),
research: Annotation<string[]>({ default: () => [] }),
draft: Annotation<string>(),
critique: Annotation<string>(),
iterations: Annotation<number>({ default: () => 0 }),
});
const model = new ChatOpenAI({ model: "gpt-5" });
const graph = new StateGraph(State)
.addNode("research", researchNode)
.addNode("draft", draftNode)
.addNode("critique", critiqueNode)
.addEdge("__start__", "research")
.addEdge("research", "draft")
.addEdge("draft", "critique")
.addConditionalEdges("critique", (s) =>
s.iterations < 2 && needsMoreWork(s.critique) ? "research" : "__end__"
)
.compile({ checkpointer: new MemorySaver() });That graph supports pausing for human review, resuming from a checkpoint after a crash, and replaying execution for debugging. Building the equivalent on top of the AI SDK is a meaningful engineering project. For the patterns where it earns its keep, see the agentic RAG architecture guide.
What each one does badly
Both frameworks have rough edges that show up in production. Knowing them in advance saves you a sprint of frustration.
AI SDK weaknesses. It has no real document loader ecosystem - if you need to ingest 14 different file types, you are either writing wrappers or pulling in LangChain. The agent abstractions are deliberately minimal; for anything with cycles, retries, or persistent state, you build the orchestration yourself. Some provider-specific features lag behind native SDKs by a release or two. And the React hooks are great if you are on Next.js, less compelling on other frameworks.
LangChain weaknesses. Bundle bloat is real if you do not import carefully - the meta package pulls in hundreds of KB you do not need. Abstractions leak: when something breaks, the debugger drops you into LangChain internals before the actual problem. API churn is faster than the AI SDK; I have seen deprecated chain APIs broken in minor releases. LangSmith is great but creates gravity toward staying on the LangChain stack for observability. And the documentation, while extensive, is fragmented across langchain, langchain-core, langgraph, and a constellation of provider packages.
The hybrid pattern that ships
For any serious AI project, the architecture I default to is a hybrid. The AI SDK handles everything user-facing: the chat UI, the streaming endpoints, the structured output extraction, the simple tool calls. LangGraph handles the heavy orchestration: multi-step research agents, document ingestion pipelines, anything with cycles or human-in-the-loop pauses.
The two components live in different runtimes. The AI SDK code runs in Next.js routes or Vercel Functions where cold start and bundle size matter. The LangGraph code runs in a Node worker, a background queue, or a long-running Vercel Function where the bundle penalty is amortized over many requests. They communicate through plain JSON over HTTP or a message queue - no shared types, no shared runtime, no leaky abstractions.
Concretely: a research agent UI in a Next.js app would have a useChat-powered frontend pointing at an AI SDK route. That route kicks off a LangGraph run on a separate worker (Inngest, a queue, or a long-running route), streams intermediate updates back through a Server-Sent Events bridge, and writes the final result to the database. The user sees the AI SDK's smooth streaming UX; the backend uses LangGraph's graph runtime where it actually pays off. Neither framework is in the wrong place.
Bundle size and Lambda cold start: the real numbers
These are measurements from a representative Next.js 15 app I keep as a benchmark harness. Same route, same model call, same Vercel deployment region, measured across 200 cold invocations each.
| Setup | Gzipped bundle | p50 cold start | p95 cold start | p50 warm |
|---|---|---|---|---|
| AI SDK + @ai-sdk/openai | ~52 KB | 320 ms | 460 ms | 18 ms |
| AI SDK + AI Gateway | ~48 KB | 305 ms | 440 ms | 16 ms |
| LangChain (lean: core + openai) | ~118 KB | 410 ms | 620 ms | 22 ms |
| LangChain (meta package) | ~310 KB | 680 ms | 1,100 ms | 28 ms |
| LangChain + LangGraph + retrievers | ~370 KB | 740 ms | 1,250 ms | 32 ms |
The warm numbers are close enough that they do not matter for most apps. The cold numbers are not. If your route fires sporadically, which is most B2B SaaS, the LangChain cold start tax is paid on a meaningful fraction of real user requests. For a consumer chat app with constant traffic, it amortizes. Pick accordingly.
Streaming UI head-to-head
Streaming is where the AI SDK's opinionated design pays off most visibly. Here is a working chat component with the AI SDK:
"use client";
import { useChat } from "@ai-sdk/react";
export function Chat() {
const { messages, input, handleInputChange, handleSubmit, status } = useChat({
api: "/api/chat",
});
return (
<div className="flex flex-col gap-3">
{messages.map((m) => (
<div key={m.id} className={m.role === "user" ? "text-right" : ""}>
<strong>{m.role}:</strong> {m.content}
</div>
))}
<form onSubmit={handleSubmit}>
<input value={input} onChange={handleInputChange} disabled={status !== "ready"} />
</form>
</div>
);
}That is the complete client. Message state, optimistic updates, streaming partial responses, tool call rendering, and disabled input during generation - all handled. The equivalent with LangChain JS requires you to set up your own stream reader, parse the chunks, manage message state, and wire up tool call rendering yourself. It is not hard, but it is 60 to 100 lines instead of 15.
LangChain's streaming story shines elsewhere: streaming intermediate events from a long-running graph, where you want to see "searching the web," "reading PDF 3 of 7," and so on. LangGraph emits structured events at every node transition; useChat is not designed for that. This is the dividing line. Use useChat for chat. Use LangGraph event streams for agentic UIs that show their work. This pattern is covered in the streaming tutorial with full code.
Tool calling head-to-head
Tool calling looks similar in both frameworks until you ship it. The AI SDK's tool API is closer to the underlying provider semantics - Zod schema in, typed execute function, automatic parallel calls when the model emits them, automatic message threading for multi-step tool use.
// Vercel AI SDK: tool calling
import { streamText, tool } from "ai";
import { z } from "zod";
const result = streamText({
model: openai("gpt-5"),
messages,
tools: {
searchDocs: tool({
description: "Search the internal knowledge base",
parameters: z.object({
query: z.string(),
topK: z.number().min(1).max(20).default(5),
}),
execute: async ({ query, topK }) => {
return await retriever.search(query, topK);
},
}),
},
maxSteps: 5,
});LangChain's equivalent:
// LangChain JS: tool calling
import { ChatOpenAI } from "@langchain/openai";
import { tool } from "@langchain/core/tools";
import { z } from "zod";
const searchDocs = tool(
async ({ query, topK }) => retriever.search(query, topK),
{
name: "searchDocs",
description: "Search the internal knowledge base",
schema: z.object({
query: z.string(),
topK: z.number().min(1).max(20).default(5),
}),
}
);
const model = new ChatOpenAI({ model: "gpt-5" }).bindTools([searchDocs]);
// You then drive the tool-call loop manually or with createToolCallingAgentThe LangChain version is more code and you still have to wire the multi-step loop yourself unless you use createToolCallingAgent or LangGraph's prebuilt agent. The AI SDK does it inline with maxSteps. For more on getting tool design right regardless of framework, see the tool calling best practices guide - 80% of agent failures come from bad tool design, not bad framework choice.
RAG head-to-head
RAG is where the two frameworks diverge most. The AI SDK gives you nothing for retrieval - you bring your own vector store query, you stuff context into the prompt, you call streamText. That is the whole pattern.
// AI SDK + your own retrieval
import { streamText } from "ai";
import { searchVectorStore } from "@/lib/retrieval";
export async function POST(req: Request) {
const { messages } = await req.json();
const userQuery = messages[messages.length - 1].content;
const chunks = await searchVectorStore(userQuery, { topK: 6 });
const context = chunks.map((c, i) => `[${i + 1}] ${c.text}`).join("\n\n");
return streamText({
model: openai("gpt-5"),
system: `Answer using only the provided context. Cite sources as [n].\n\nContext:\n${context}`,
messages,
}).toDataStreamResponse();
}That is roughly 12 lines for a working RAG endpoint. It is intentional - the AI SDK refuses to opine on retrieval, which means you control reranking, hybrid search, query rewriting, and filtering directly.
LangChain takes the opposite approach. The LCEL retrieval chain bundles retriever, prompt template, model, and output parser into one composable pipeline:
// LangChain LCEL retrieval chain
import { ChatOpenAI } from "@langchain/openai";
import { ChatPromptTemplate } from "@langchain/core/prompts";
import { RunnableSequence } from "@langchain/core/runnables";
import { StringOutputParser } from "@langchain/core/output_parsers";
const prompt = ChatPromptTemplate.fromTemplate(`
Answer using only the provided context. Cite sources as [n].
Context: {context}
Question: {question}
`);
const chain = RunnableSequence.from([
{
context: async (input) => {
const docs = await retriever.invoke(input.question);
return docs.map((d, i) => `[${i + 1}] ${d.pageContent}`).join("\n\n");
},
question: (input) => input.question,
},
prompt,
new ChatOpenAI({ model: "gpt-5" }),
new StringOutputParser(),
]);
const stream = await chain.stream({ question: userQuery });Either pattern works. The AI SDK version is more readable for simple RAG. The LangChain version composes better when you start adding query rewriting, reranking, parent-document retrieval, and multi-query expansion as additional Runnables. For the full production-grade RAG architecture either way, see the RAG architecture tutorial.
My picks by scenario
These are concrete recommendations I would give a friend at each stage. None are absolute - bring exotic cases to a scoping call.
Next.js chat app: Vercel AI SDK, useChat, no contest. LangChain adds nothing here and costs you bundle and cold start.
Internal agent with tool calling and 2-3 steps: AI SDK with maxSteps. Building the same on LangChain requires createToolCallingAgent or a LangGraph graph, which is more infrastructure than the problem deserves.
Multi-step workflow with branches, cycles, or human-in-the-loop: LangGraph. The checkpointing and pause primitives are worth the bundle weight. Run it in a worker, not in a Vercel Function, and let an AI SDK route stream the events to the UI.
Production RAG with custom retrieval: AI SDK in the query path, LangChain loaders in the ingestion pipeline. Your retrieval logic is yours and lives behind a thin interface - the same way I recommend wrapping the vector store in the RAG tutorial.
Quick prototype: AI SDK. The fastest path to a working demo, especially with the AI Gateway for instant provider swapping.
Document-heavy ingestion (Notion, Confluence, GitHub, PDFs): LangChain loaders in a background job. Nothing else has the coverage. Serve queries with the AI SDK.
Heavy multi-agent system with handoffs: LangGraph on a worker. The graph model maps cleanly onto multi-agent topologies, and the durable state means you can resume after crashes instead of restarting.
Migration paths: shedding LangChain weight
If you started on LangChain and the bundle is hurting, the migration is usually less work than you fear. The path I follow with clients:
First, draw the boundary. Identify which routes need streaming UI and which routes are batch or background work. The streaming UI routes are the AI SDK targets. The background work stays on LangChain or LangGraph for now.
Second, replace the streaming chain with streamText plus a thin retrieval call. Most LCEL chains in customer-facing routes are retriever-prompt-model-parser. That maps to roughly 15 lines of AI SDK code. The Zod tool schemas port over directly.
Third, move ingestion to a background job. The LangChain loaders and retriever-building code goes into a Node script or a queue worker. The user-facing routes never import langchain anymore. Bundle drops by 200+ KB overnight, cold start improves by 300 to 500 ms.
Fourth, decide on LangGraph case by case. If you have a real graph - cycles, checkpoints, human-in-the-loop - keep it on LangGraph in a worker. If you have a 3-step linear workflow that someone built on LangGraph because it was familiar, port it to plain AI SDK control flow. Most "agents" are workflows in disguise, which is the point I make in the workflow vs agent post.
This is the same migration I ran for the AI features inside Caldra AI. The original prototype was LangChain end-to-end because that was the fastest path in early 2024. By mid-2025 the production endpoints were AI SDK with LangChain only in the ingestion worker. Bundle on the hot path dropped from 290 KB to 58 KB and cold starts halved. Nothing else changed.
Frequently asked questions
These are the questions I get most often when teams scope a new AI feature with me. The answers are also embedded as FAQ structured data.
Should I use LangChain or Vercel AI SDK in 2026?
For most TypeScript apps, use the Vercel AI SDK for the application endpoints and useChat for the UI. Reach for LangChain only when you need its loader and retriever ecosystem or LangGraph for stateful, multi-step orchestration. The hybrid pattern - AI SDK at the edges, LangGraph in a separate worker for heavy graphs - is what I ship for serious projects.
Is LangChain dead in 2026?
No, but the JS version got leaner. The original LangChain JS chains are largely deprecated in favor of LCEL and LangGraph. langchain-core is small, langgraph is the real value, and the ecosystem of document loaders and retrievers still has no real equivalent. The mistake is importing the kitchen-sink langchain package into a Lambda - that is where the bundle bloat reputation comes from.
How much smaller is Vercel AI SDK than LangChain JS?
On a typical Next.js API route, the AI SDK adds around 45 to 60 KB gzipped including a provider. A naive LangChain JS install with the meta package easily crosses 280 to 350 KB gzipped before you write a line of business logic. With tree-shaking and importing only langchain-core plus langgraph you can get LangChain under 120 KB, but it still costs you more cold-start time than the AI SDK.
Can I use LangChain and Vercel AI SDK together?
Yes, and that is the pattern I recommend for anything past a basic chat app. The AI SDK handles the streaming UI, useChat hook, and front-of-house endpoints. LangGraph handles the multi-step orchestration in a separate worker, queue, or background route. The two talk to each other through plain JSON or events, not through SDK adapters.
Does Vercel AI SDK support tool calling and structured output?
Yes, both are first-class. streamText and generateText accept a tools object with Zod schemas, parallel tool calls work out of the box, and generateObject gives you typed structured output with automatic retries on schema failures. For most production tool-calling needs in a Next.js app, you do not need LangChain at all.
Is LangGraph worth the complexity?
For stateful agents with cycles, retries, human-in-the-loop pauses, and durable state, yes. LangGraph gives you a real graph runtime with checkpointing and time travel that you would otherwise build yourself. For linear two or three step workflows, the AI SDK with manual control flow is simpler and ships faster.
What about LangChain document loaders for RAG?
This is the strongest remaining argument for LangChain in 2026. The loader and retriever ecosystem covers PDFs, Notion, Confluence, GitHub, web pages, and dozens of other sources with maintained code. The AI SDK has no equivalent. The pragmatic pattern is to run loaders in an ingestion job using LangChain and serve queries from your own retrieval code using the AI SDK.
Which one has better observability?
LangSmith is tightly integrated with LangChain and LangGraph and is the easiest observability story if you are all-in on that stack. The AI SDK works with any tracing tool that wraps fetch or the provider SDKs - Langfuse, Helicone, Braintrust, and OpenTelemetry exporters all work. Neither has a clear win; pick the observability tool first and the framework will adapt.
Closing
The framework wars are mostly over. In 2026 the Vercel AI SDK is the default for TypeScript AI app code, LangChain is the default for ingestion and stateful orchestration, and the boring answer of using both in their right place is what ships. The mistakes I see weekly are picking one for everything: kitchen-sink LangChain on a Next.js consumer app that cold-starts in 1.2 seconds, or hand-rolled control flow on top of the AI SDK that should have been a LangGraph graph. Start with the AI SDK. Add LangChain when a specific need pushes you there. Run them in different runtimes so the bundle penalty stays where it pays for itself. That is the whole playbook. If you want help applying it to a specific codebase, that is exactly the kind of scoping I do under AI integration and AI agent development, and the Eastern-Europe-rate version through hire an AI developer in Kosovo.