Back to Blog
AINext.jsOpenAIFull-Stack

Building AI Web Apps with Next.js & OpenAI

4 min read
Building AI Web Apps with Next.js & OpenAI

Artificial Intelligence is no longer just a buzzword; it is a core business requirement. Almost every client I work with today asks the same question: "Can we add AI to this?"

Whether it is a customer support chatbot, an automated content generator, or intelligent data analysis, integrating Large Language Models (LLMs) like OpenAI's GPT-4 into a web application has become a mandatory skill for modern Full-Stack Architects.

In this guide, I will show you how to securely integrate the OpenAI API into a Next.js 16 (App Router) application and stream the response to the frontend for a seamless, native feel.

1. The Security Challenge

The biggest mistake junior developers make when integrating AI is calling the OpenAI API directly from the client side (the browser). Never do this.

If you expose your OPENAI_API_KEY to the client, malicious users can steal it and run up a massive bill on your account.

As a Full-Stack Architect, you must always proxy AI requests through a secure backend server. Thanks to Next.js 16 Route Handlers (app/api), we can build this secure proxy in seconds.

2. Setting up the API Route

First, install the official OpenAI SDK:

npm install openai

Next, create a secure Route Handler. We will use the Edge Runtime for maximum performance and minimal latency.

// app/api/chat/route.ts
import { OpenAI } from "openai";
import { NextResponse } from "next/server";

// Initialize the OpenAI client securely on the server
const openai = new OpenAI({
  apiKey: process.env.OPENAI_API_KEY,
});

// Use the Edge runtime for faster response times
export const runtime = "edge";

export async function POST(req: Request) {
  try {
    const { prompt } = await req.json();

    if (!prompt) {
      return NextResponse.json(
        { error: "Prompt is required" },
        { status: 400 },
      );
    }

    const response = await openai.chat.completions.create({
      model: "gpt-4o",
      messages: [{ role: "user", content: prompt }],
      temperature: 0.7,
    });

    return NextResponse.json({ result: response.choices[0].message.content });
  } catch (error) {
    console.error("OpenAI Error:", error);
    return NextResponse.json(
      { error: "Failed to fetch AI response" },
      { status: 500 },
    );
  }
}

3. Streaming Responses (The Pro Way)

The code above works perfectly, but there's a UX issue: AI models take time to generate text. If you wait for the entire response to finish before sending it to the client, the user might stare at a loading spinner for 5-10 seconds.

To fix this, we use Server-Sent Events (SSE) and Streaming. This is how ChatGPT types out the response word-by-word on your screen.

Luckily, Next.js and the ai package by Vercel make this incredibly easy.

// Optimized Streaming Approach
import { OpenAIStream, StreamingTextResponse } from "ai";
import { OpenAI } from "openai";

const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
export const runtime = "edge";

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

  // Ask OpenAI for a streaming chat completion
  const response = await openai.chat.completions.create({
    model: "gpt-4o",
    stream: true,
    messages,
  });

  // Convert the response into a friendly text-stream
  const stream = OpenAIStream(response);

  // Respond with the stream
  return new StreamingTextResponse(stream);
}

4. The Frontend Implementation

Now, connecting this to our React frontend is a breeze using the useChat hook provided by Vercel's AI SDK.

"use client";

import { useChat } from "ai/react";

export default function Chatbot() {
  const { messages, input, handleInputChange, handleSubmit } = useChat();

  return (
    <div className="flex flex-col w-full max-w-md py-24 mx-auto stretch">
      {messages.map((m) => (
        <div key={m.id} className="whitespace-pre-wrap mb-4">
          <strong>{m.role === "user" ? "You: " : "AI: "}</strong>
          {m.content}
        </div>
      ))}

      <form
        onSubmit={handleSubmit}
        className="fixed bottom-0 w-full max-w-md p-2 mb-8 border border-gray-300 rounded shadow-xl"
      >
        <input
          className="w-full p-2 bg-transparent outline-none"
          value={input}
          placeholder="Say something..."
          onChange={handleInputChange}
        />
      </form>
    </div>
  );
}

The Architect's Verdict

Building AI-powered features is no longer a dark art. By leveraging Next.js Route Handlers and Edge Functions, we can build secure, incredibly fast, and scalable AI applications.

Remember, the key to a professional architecture is Security (hiding API keys on the server) and UX (streaming responses to avoid long loading times).

Need an AI-powered SaaS or custom integration for your business? Check out my Services or reach out directly!

Enjoyed the article?

Let's connect on social media or discuss how we can work together on your next project.

Let's Talk