Vercel AI SDK · Next.js + Node + Edge
Vercel AI SDK + Leanroute
The Vercel AI SDK's @ai-sdk/openai provider accepts a baseURL via its createOpenAI factory. Build the factory once, import it wherever you use generateText, streamText, useChat, or generateObject — every call routes through Leanroute.
1. Install + get a gateway key
npm install ai @ai-sdk/openai
# or: pnpm add ai @ai-sdk/openai
# or: bun add ai @ai-sdk/openaiFrom /dashboard/keys create a key labeled "vercel-ai-sdk". Add it to .env.local as LEANROUTE_API_KEY=gw_live_....
2. Build the provider factory
One file, import it across your app. Never inline the key in checked-in code — keep it in an env var so the browser bundle can't leak it.
// lib/leanroute.ts
import { createOpenAI } from "@ai-sdk/openai";
// One factory, use across your whole Next.js app. Wire the API key
// via env var — never inline the gw_live_* string in checked-in code.
export const leanroute = createOpenAI({
baseURL: "https://api.leanroute.dev/v1",
apiKey: process.env.LEANROUTE_API_KEY!,
});3. Non-streaming: generateText
import { generateText } from "ai";
import { leanroute } from "@/lib/leanroute";
const { text } = await generateText({
model: leanroute("anthropic/claude-sonnet-4-6"),
prompt: "Explain server-side rendering in one sentence.",
});
console.log(text);4. Streaming route handler (Next.js App Router)
Runs on the Edge runtime for lowest first-token latency. Server-sent events are forwarded from the upstream provider chunk-by-chunk with no intermediate buffering.
// app/api/chat/route.ts
import { streamText } from "ai";
import { leanroute } from "@/lib/leanroute";
export const runtime = "edge";
export async function POST(req: Request) {
const { messages } = await req.json();
const result = streamText({
model: leanroute("anthropic/claude-sonnet-4-6"),
messages,
});
return result.toDataStreamResponse();
}5. useChat React hook
Client component that talks to your /api/chat route above. The hook handles message state, streaming updates, and form input for you.
// app/chat/page.tsx
"use client";
import { useChat } from "ai/react";
export default function Chat() {
const { messages, input, handleInputChange, handleSubmit } = useChat({
api: "/api/chat",
});
return (
<div>
{messages.map((m) => (
<p key={m.id}>
<strong>{m.role}:</strong> {m.content}
</p>
))}
<form onSubmit={handleSubmit}>
<input value={input} onChange={handleInputChange} />
</form>
</div>
);
}6. Structured output: generateObject
Zod-validated JSON output from any model that supports function calling upstream. Leanroute forwards the schema to the provider unchanged.
import { generateObject } from "ai";
import { z } from "zod";
import { leanroute } from "@/lib/leanroute";
const { object } = await generateObject({
model: leanroute("openai/gpt-4o"),
schema: z.object({
summary: z.string(),
tags: z.array(z.string()),
}),
prompt: "Summarize: LLM gateways route API calls across providers.",
});
console.log(object.tags); // e.g. ["llm", "infrastructure"]Troubleshooting
- 401 unauthenticated: issue a new key at /dashboard/keys.
- 400 unknown_model: the SDK passes the model string as-is. Use the canonical
provider/modelform (e.g.openai/gpt-4o, notgpt-4o). - Key visible in browser DevTools: you wired the factory in a client component. Move it to a route handler (server-side) and call your own
/api/chatfrom the client viauseChat. - CORS errors on client-side fetches: you probably tried to call
api.leanroute.devfrom the browser directly. Always proxy through your own route handler.