Skip to main content
Lesson 6 of 12 · Chat Completions: OpenAI Compatibility

Vercel AI SDK and Frontend Integration

Lesson 6 of 12 Updated November 3, 2026 Developer
On this page
  1. The Vercel AI SDK for Web Applications
  2. Installation
  3. Server Side: Generating Text
  4. Server-Side Streaming
  5. Client Side: The useChat Hook
  6. Corresponding API Route
  7. Key Takeaways

Updated November 3, 2026 based on AI SDK 7 documentation (ai 7.0.x, @ai-sdk/react 4.x): useChat works with DefaultChatTransport and sendMessage, messages display via parts, the route returns createUIMessageStreamResponse, system becomes instructions, and the @ai-sdk/xai 5 provider no longer supports Chat Completions: xai() uses the Responses API (code verified with TypeScript compiler using ai 7.0.162 and @ai-sdk/xai 5.0.38). The previous version used the AI SDK 4 API (input, handleSubmit, isLoading, toDataStreamResponse). Sources: AI SDK, Chatbot · AI SDK, xAI provider.

The Vercel AI SDK for Web Applications

The Vercel AI SDK is a TypeScript framework designed to integrate AI models into web applications. It provides React hooks, streaming utilities, and a unified abstraction that natively supports xAI/Grok via the @ai-sdk/xai package.

If you’re building a Next.js, Nuxt, SvelteKit, or any React application that needs to display streaming responses, the Vercel AI SDK simplifies the work significantly.

Installation

Install the core SDK and the xAI provider:

npm install ai @ai-sdk/xai

Configure your API key in the environment variables:

# .env.local
XAI_API_KEY=your-api-key

Server Side: Generating Text

The generateText function is the simplest equivalent of client.chat.create(). One thing has changed, and it concerns this course directly: since version 5 of the @ai-sdk/xai provider (September 2026), compatible with AI SDK 7, the provider no longer supports the Chat Completions endpoint. xai(model) uses the Responses API, which xAI now recommends. The xai.chat(model) method, which some migration guides still cite, existed only in provider version 4; for code that must stay on Chat Completions, use the OpenAI SDK pointed at xAI instead (Lesson 5).

import { generateText } from "ai";
import { xai } from "@ai-sdk/xai";

const { text } = await generateText({
  model: xai("grok-4.7"), // xAI Responses API
  instructions: "You are a technical assistant.",
  prompt: "Explain the concept of containerization.",
});

console.log(text);

The xai provider automatically reads XAI_API_KEY from the environment; createXai() lets you create an instance with custom settings. The instructions option replaces system, which is still accepted but deprecated in AI SDK 7.

Server-Side Streaming

For streaming, use streamText. The response reads chunk by chunk from textStream:

import { streamText } from "ai";
import { xai } from "@ai-sdk/xai";

const result = streamText({
  model: xai("grok-4.7"),
  instructions: "You are a teaching assistant.",
  messages: [
    { role: "user", content: "How does a relational database work?" },
  ],
});

for await (const chunk of result.textStream) {
  process.stdout.write(chunk);
}

Client Side: The useChat Hook

The useChat hook is the centerpiece on the frontend. It handles conversation history, streaming, and request state; the input field, however, remains a simple React state that you manage:

"use client";
import { useChat } from "@ai-sdk/react";
import { DefaultChatTransport } from "ai";
import { useState } from "react";

export default function ChatPage() {
  const { messages, sendMessage, status } = useChat({
    transport: new DefaultChatTransport({ api: "/api/chat" }),
  });
  const [input, setInput] = useState("");

  return (
    <div>
      {messages.map((m) => (
        <div key={m.id}>
          <strong>{m.role === "user" ? "You" : "Grok"}</strong>
          {m.parts.map((part, i) =>
            part.type === "text" ? <p key={i}>{part.text}</p> : null
          )}
        </div>
      ))}

      <form
        onSubmit={(e) => {
          e.preventDefault();
          if (input.trim()) {
            sendMessage({ text: input });
            setInput("");
          }
        }}
      >
        <input
          value={input}
          onChange={(e) => setInput(e.target.value)}
          placeholder="Ask your question..."
          disabled={status !== "ready"}
        />
        <button type="submit" disabled={status !== "ready"}>
          Send
        </button>
      </form>
    </div>
  );
}

What useChat Handles Automatically

  • Message history: Accumulates exchanges; each message carries parts (text, tool calls…), display these rather than the old content field
  • Streaming: Displays the response as it generates
  • Request state: status is ready when a new message can be sent
  • Error handling: Intercepts network and API errors
  • Cancellation: stop() interrupts an ongoing generation

Corresponding API Route

The hook expects a route that returns a stream of UI messages. Here is the implementation with the Next.js App Router, modeled after the official AI SDK 7 example:

// app/api/chat/route.ts
import {
  convertToModelMessages,
  createUIMessageStreamResponse,
  streamText,
  toUIMessageStream,
  type UIMessage,
} from "ai";
import { xai } from "@ai-sdk/xai";

export async function POST(req: Request) {
  const { messages }: { messages: UIMessage[] } = await req.json();

  const result = streamText({
    model: xai("grok-4.7"),
    instructions: "You are a helpful assistant. Respond in English.",
    messages: await convertToModelMessages(messages),
  });

  return createUIMessageStreamResponse({
    stream: toUIMessageStream({ stream: result.stream }),
  });
}

Two conversions wrap the exchange: convertToModelMessages transforms UI messages received from the client into model messages, and toUIMessageStream does the reverse on the response stream. The toUIMessageStreamResponse() methods on the streamText result still work in AI SDK 7, but they are deprecated; as for the old toDataStreamResponse(), it no longer exists.

Key Takeaways

  • The Vercel AI SDK supports xAI/Grok via the @ai-sdk/xai package
  • generateText for synchronous responses, streamText for streaming
  • The useChat hook manages the complete state of a conversation on the client
  • createUIMessageStreamResponse and toUIMessageStream return the stream expected by useChat; toDataStreamResponse() no longer exists
  • Since @ai-sdk/xai 5, the provider no longer supports Chat Completions: xai() uses the Responses API; to stay on Chat Completions, use the OpenAI SDK
  • The createXai() provider automatically detects the API key in the environment