Connect Anthropic with Next.js
Implementation Guide
Overview: Connecting Anthropic and Next.js
Integrating the Anthropic API with a Next.js application is one of the most architecturally nuanced patterns in modern AI-powered product development. The Anthropic API exposes Claude — a family of large language models — through a messages endpoint that supports both synchronous JSON responses and Server-Sent Events (SSE) streaming. Next.js, with its App Router, provides a first-class mechanism for handling both patterns: Route Handlers for the API layer, React Server Components for server-side inference calls, and the Vercel AI SDK (or manual SSE parsing) for streaming tokens to Client Components in real time.
The central challenge when connecting Anthropic to Next.js is not simply making an API call — it is deciding where in the Next.js rendering architecture the inference call should live (Route Handler vs. Server Component vs. Edge Function), managing streaming state across the server-client boundary, handling tool use (function calling) response cycles, and ensuring that API keys are never exposed to the browser. This guide covers all of these concerns in depth, with specific attention to the @anthropic-ai/sdk Node.js client, the Vercel AI SDK's anthropic provider adapter, and direct fetch-based SSE streaming for environments where the SDK is unavailable.
Core Prerequisites
You must have an Anthropic API key with sufficient credit balance and access to the model you intend to invoke. API keys are created at console.anthropic.com and must be stored as a server-side environment variable named ANTHROPIC_API_KEY. This key must never be prefixed with NEXT_PUBLIC_ — doing so would embed it in the browser bundle. Anthropic's API uses Bearer token authentication; there is no OAuth 2.0 flow required for server-to-server calls. The required request header is x-api-key: <YOUR_KEY> combined with anthropic-version: 2023-06-01.
On the Next.js side, you need version 13.4 or later for App Router Route Handler support. Install @anthropic-ai/sdk (v0.26.x or later) via npm. If using the Vercel AI SDK for streaming UI, install ai (v3.x) and @ai-sdk/anthropic. Node.js 18+ is required for the native fetch and ReadableStream APIs used in streaming implementations. If deploying to Vercel Edge Runtime, note that @anthropic-ai/sdk uses Node.js-specific APIs and must be configured for the nodejs runtime in your Route Handler via export const runtime = 'nodejs'.
Top Enterprise Use Cases
The primary enterprise use case is a streaming chat interface where user messages are sent to a Route Handler, forwarded to the Anthropic messages API with streaming enabled, and tokens are piped back to the browser as they arrive. This produces a ChatGPT-like typing effect with low time-to-first-token latency, which is critical for user experience in customer-facing AI applications.
The second major use case is agentic tool use. Claude's API supports a tools parameter that allows you to define callable functions. When Claude determines it needs to call a tool, it returns a tool_use content block instead of a text block. Your Next.js Route Handler must detect this block, execute the corresponding function (e.g., a database query or an external API call), and return the result to Claude in a subsequent tool_result message. This multi-turn tool use loop is the backbone of AI agents built on Next.js.
The third use case is document processing in Server Components. For workflows where a user uploads a PDF or image, you can call the Anthropic API directly inside a React Server Component using the documents or images content block types. Because Server Components run exclusively on the server, the API key is never exposed and the response can be streamed into the React component tree.
Step-by-Step Implementation Guide
Begin by creating a Route Handler at app/api/chat/route.ts. This handler accepts a POST request containing a messages array in the Anthropic messages format and returns a streaming SSE response using the Node.js ReadableStream API.
Using the @anthropic-ai/sdk directly without the Vercel AI SDK, the implementation looks like this:
import Anthropic from '@anthropic-ai/sdk';
import { NextRequest } from 'next/server';
export const runtime = 'nodejs';
const client = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY });
export async function POST(req: NextRequest) {
const { messages } = await req.json();
const stream = await client.messages.stream({
model: 'claude-sonnet-4-20250514',
max_tokens: 1024,
messages,
});
const encoder = new TextEncoder();
const readable = new ReadableStream({
async start(controller) {
for await (const event of stream) {
if (
event.type === 'content_block_delta' &&
event.delta.type === 'text_delta'
) {
controller.enqueue(encoder.encode(`data: ${JSON.stringify({ text: event.delta.text })}\n\n`));
}
}
controller.enqueue(encoder.encode('data: [DONE]\n\n'));
controller.close();
},
});
return new Response(readable, {
headers: {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive',
},
});
}
On the Client Component side, use the EventSource API or a manual fetch with getReader() to consume the SSE stream. The fetch approach is preferred because EventSource does not support POST requests. In a React Client Component, invoke the Route Handler with fetch('/api/chat', { method: 'POST', body: JSON.stringify({ messages }) }), then iterate over the response body's ReadableStream using response.body.getReader(), decode each Uint8Array chunk with TextDecoder, parse the data: prefix, and append each text delta to a local state variable.
For tool use workflows, the Route Handler must implement a recursive loop. When the Anthropic API returns a stop_reason of tool_use, your handler identifies each tool_use block in the content array, dispatches the tool call (e.g., a Supabase query for a get_user_data tool), and constructs a new message with role: 'user' containing a tool_result content block:
{
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": "toolu_01AbCdEfGhIjKlMnOpQrStUv",
"content": "{ \"user_name\": \"Alice\", \"plan\": \"enterprise\" }"
}
]
}
This message is appended to the conversation history and the API is called again. This loop repeats until Claude returns a stop_reason of end_turn, signaling that all tool calls have been resolved and a final text response is ready.
When using the Vercel AI SDK, replace the manual SSE implementation with streamText from the ai package and the anthropic provider from @ai-sdk/anthropic. The SDK handles the SSE protocol, token streaming, and the useChat React hook on the client side, reducing boilerplate significantly. However, the manual implementation is necessary when tool use requires server-side side effects that the Vercel AI SDK's built-in tool execution model does not support.
Common Pitfalls & Troubleshooting
A 401 Unauthorized response from the Anthropic API always indicates an invalid or missing ANTHROPIC_API_KEY. Verify the key is set correctly in your Vercel project's environment variables for the Production environment and has not been accidentally prefixed with NEXT_PUBLIC_. A common mistake is setting the variable in .env.local but not in the Vercel dashboard, causing the deployed function to fail while local development works.
A 529 Overloaded error is Anthropic-specific and indicates the API is under high load. This is not a client error. Implement exponential backoff with jitter: start with a 1-second delay, double on each retry, and cap at 30 seconds. Limit to 3 retries before surfacing an error to the user.
A 400 Bad Request with the message messages: roles must alternate between user and assistant means your conversation history has consecutive messages with the same role. This is a strict requirement of the Anthropic messages format — every user message must be followed by an assistant message and vice versa. Audit your message array construction logic, particularly in multi-turn tool use loops where a tool_result message must always have role: 'user'.
Streaming timeouts on Vercel deployments occur because the default maximum function execution duration is 10 seconds on Hobby plans. For long-running Claude streams, upgrade to Pro (60-second limit) or configure export const maxDuration = 60 in your Route Handler. For responses that may exceed 60 seconds, consider switching to a background job pattern using Vercel's waitUntil or a queue-based architecture.