← Blog

Claude API Next.js Integration Example

2026-10-19 · 5 min read · SubToAPI Team

What a Claude API Next.js integration actually looks like

If you're searching for a working example, you probably want three things: a server-side route that calls Claude without exposing your key to the browser, a way to stream tokens back to the UI as they arrive, and a client component that renders the response. This article walks through all three using the Next.js App Router, with code you can copy directly into a project.

The pattern is the same whether you're calling Claude directly through Anthropic's SDK or through an HTTPS gateway like SubToAPI — a server route holds the API key, the browser never sees it, and the client talks only to your own /api/* endpoints. We'll use SubToAPI's REST endpoint in the examples because it keeps the HTTP layer identical to a standard fetch call, which makes the Next.js route handler simpler to reason about.

Project setup

Start with a standard Next.js app (App Router):

npx create-next-app@latest claude-chat
cd claude-chat

Add your key to .env.local. Never prefix it with NEXT_PUBLIC_ — that would ship it to the browser.

SUBTOAPI_KEY=sub_live_xxxxxxxxxxxxxxxx

If you don't have a key yet, sign up at /signup — it reuses your existing Claude access and gives you a sub_live_... key you can drop straight into server code. See /docs/quickstart for the full setup flow.

Server-side API route

Create app/api/chat/route.js. This is where the Claude call happens — it runs on the server, so the key stays private.

export async function POST(req) {
  const { messages } = await req.json();

  const response = await fetch('https://api.subtoapi.app/v1/messages', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${process.env.SUBTOAPI_KEY}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      model: 'claude-sonnet-4-5',
      max_tokens: 1024,
      messages,
    }),
  });

  if (!response.ok) {
    return new Response(await response.text(), { status: response.status });
  }

  const data = await response.json();
  return Response.json(data);
}

This mirrors the Anthropic Messages API shape, so if you've used Claude before, nothing here is new. Full request/response fields are documented at /docs/messages.

Calling it from a client component

'use client';
import { useState } from 'react';

export default function Chat() {
  const [input, setInput] = useState('');
  const [reply, setReply] = useState('');

  async function send() {
    const res = await fetch('/api/chat', {
      method: 'POST',
      body: JSON.stringify({
        messages: [{ role: 'user', content: input }],
      }),
    });
    const data = await res.json();
    setReply(data.content[0].text);
  }

  return (
    <div>
      <input value={input} onChange={(e) => setInput(e.target.value)} />
      <button onClick={send}>Send</button>
      <p>{reply}</p>
    </div>
  );
}

That's a complete, working round trip: client → Next.js route → Claude → back to the client. No key ever leaves your server.

Streaming responses in Next.js

A non-streamed response feels slow for anything longer than a sentence. Next.js route handlers support streaming natively using ReadableStream, and Claude's API returns Server-Sent Events when stream: true is set.

export async function POST(req) {
  const { messages } = await req.json();

  const upstream = await fetch('https://api.subtoapi.app/v1/messages', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${process.env.SUBTOAPI_KEY}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      model: 'claude-sonnet-4-5',
      max_tokens: 1024,
      stream: true,
      messages,
    }),
  });

  return new Response(upstream.body, {
    headers: {
      'Content-Type': 'text/event-stream',
      'Cache-Control': 'no-cache',
    },
  });
}

Because upstream.body is already a ReadableStream, you can pipe it straight through without buffering the whole response in memory — important if you're running on a serverless or edge runtime with execution time limits.

On the client, read the stream with EventSource-style parsing or a small reader loop:

const res = await fetch('/api/chat', { method: 'POST', body: JSON.stringify({ messages }) });
const reader = res.body.getReader();
const decoder = new TextDecoder();

while (true) {
  const { done, value } = await reader.read();
  if (done) break;
  const chunk = decoder.decode(value);
  // parse SSE lines starting with "data: " and append text deltas to state
}

Details on event types and delta formats are in /docs/streaming. Getting this right the first time saves you from the common bug of rendering duplicate or out-of-order tokens — always append deltas, never replace the full text on each chunk.

Adding tool use

If your Next.js app needs Claude to call functions — looking up order status, querying a database, hitting an internal API — define tools in the request body and handle the tool_use stop reason server-side before sending a follow-up message with the tool result. The shape is identical to the Messages API; see /docs/tools for the schema. This is where a Next.js server route earns its keep: it can execute the actual tool call (e.g., a Postgres query) in the same request/response cycle, something you can't safely do from the browser.

Why route through an HTTPS API layer

You can call Anthropic's SDK directly from a Node runtime, but a lot of teams building Next.js apps end up wanting simple HTTPS key management instead of SDK credential plumbing — especially once multiple developers or a frontend/backend split is involved. SubToAPI turns your existing Claude access into a standard API key (sub_live_...) with usage metadata and per-seat access, which fits naturally into the environment-variable pattern Next.js already uses. Plans start at €9/month for solo use, with team and scale tiers for shared keys — see /pricing.

Deployment notes

Questions

Do I need the official Anthropic SDK to use Claude in Next.js? No. Both the route handler and streaming examples above use plain fetch, which works in any Next.js runtime (Node or edge) without adding SDK dependencies.

Can I stream Claude responses from a Next.js API route? Yes. Pipe the upstream ReadableStream directly through your route handler's Response object, as shown above, instead of buffering the full reply first.

Where should I store my API key in a Next.js project? In .env.local (or your host's environment variable settings) without the NEXT_PUBLIC_ prefix, so it's only accessible from server-side route handlers.

Turn your Claude access into an HTTPS API

SubToAPI gives you application API keys, streaming, tool use and usage insights on top of your existing Claude access — set up in minutes.

Start free  Read the quickstart →