I Built a ChatGPT Clone Using Next.js & OpenAI API – Here’s What Happened

By Dhanian Artificial Intelligence is transforming how we interact with applications—and as a developer, I wanted to dive in and experience that firsthand. So I challenged myself to build a ChatGPT-like application using Next.js 15, TypeScript, TailwindCSS, and the OpenAI API. Spoiler alert: it was surprisingly simple—and incredibly fun. Here's everything I learned, how I built it step-by-step, and what you should know if you're planning to build one too. Why Build a ChatGPT Clone? I chose this project because: It's a real-world application of AI. It helps you learn API integration, UI/UX design, state management, and async communication. It’s highly customizable—you can turn it into a customer support bot, coding assistant, or even a SaaS tool. Tech Stack Breakdown Here’s what I used: Next.js 15 (App Router): For server/client rendering and routing. TailwindCSS: For quick and responsive UI styling. OpenAI API: For chat capabilities. TypeScript: For type safety and better dev experience. React Hooks (useState, useEffect): To manage messages. Project Architecture /chatgpt-clone │ ├── app/ │ ├── page.tsx --> Main chat page │ ├── api/ │ │ └── chat/route.ts --> API route to OpenAI │ ├── components/ │ ├── ChatWindow.tsx │ ├── Message.tsx │ ├── lib/ │ └── openai.ts --> OpenAI config │ ├── styles/ │ └── globals.css Step-by-Step Guide 1. Set Up the Next.js Project npx create-next-app@latest chatgpt-clone --typescript --app cd chatgpt-clone npm install openai tailwindcss Set up Tailwind: npx tailwindcss init -p Edit tailwind.config.js and add paths to your files. 2. Create the Chat UI /app/page.tsx: "use client" import { useState } from "react" export default function HomePage() { const [messages, setMessages] = useState([{ role: "system", content: "How can I help you today?" }]) const [input, setInput] = useState("") async function sendMessage() { const newMessages = [...messages, { role: "user", content: input }] setMessages(newMessages) setInput("") const res = await fetch("/api/chat", { method: "POST", body: JSON.stringify({ messages: newMessages }), }) const data = await res.json() setMessages([...newMessages, data.reply]) } return ( {messages.map((m, i) => ( {m.content} ))} setInput(e.target.value)} /> Send ) } 3. Connect to OpenAI API /app/api/chat/route.ts: import { OpenAI } from "openai" const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY, }) export async function POST(req: Request) { const { messages } = await req.json() const response = await openai.chat.completions.create({ model: "gpt-3.5-turbo", messages, }) const reply = response.choices[0].message return Response.json({ reply }) } Make sure you add your API key in .env.local: OPENAI_API_KEY=your_key_here What I Learned Rate limits are a real concern when working with OpenAI’s free tier. Streaming responses are the future—instant feedback improves UX. Next.js App Router is incredibly clean for separating logic. It’s super easy to build SaaS-like tools using AI APIs. What’s Next? Add authentication using NextAuth. Save chat history to Supabase or MongoDB. Enable response streaming for real-time interaction. Upgrade to GPT-4 for premium power users. Final Thoughts Building this ChatGPT clone was one of the most exciting and practical mini-projects I’ve done. If you’re a developer looking to experiment with AI, there’s no better way to start. Everything I Build Is Available Here: Source code, ebooks, and full-stack resources: codewithdhanian.gumroad.com Follow me on X for daily dev content & updates: @e_opore Let’s build cool stuff together!

Apr 15, 2025 - 05:27
 0
I Built a ChatGPT Clone Using Next.js & OpenAI API – Here’s What Happened

By Dhanian

Artificial Intelligence is transforming how we interact with applications—and as a developer, I wanted to dive in and experience that firsthand. So I challenged myself to build a ChatGPT-like application using Next.js 15, TypeScript, TailwindCSS, and the OpenAI API.

Spoiler alert: it was surprisingly simple—and incredibly fun. Here's everything I learned, how I built it step-by-step, and what you should know if you're planning to build one too.

Why Build a ChatGPT Clone?

I chose this project because:

  • It's a real-world application of AI.
  • It helps you learn API integration, UI/UX design, state management, and async communication.
  • It’s highly customizable—you can turn it into a customer support bot, coding assistant, or even a SaaS tool.

Tech Stack Breakdown

Here’s what I used:

  • Next.js 15 (App Router): For server/client rendering and routing.
  • TailwindCSS: For quick and responsive UI styling.
  • OpenAI API: For chat capabilities.
  • TypeScript: For type safety and better dev experience.
  • React Hooks (useState, useEffect): To manage messages.

Project Architecture

/chatgpt-clone
│
├── app/
│   ├── page.tsx      --> Main chat page
│   ├── api/
│   │   └── chat/route.ts  --> API route to OpenAI
│
├── components/
│   ├── ChatWindow.tsx
│   ├── Message.tsx
│
├── lib/
│   └── openai.ts     --> OpenAI config
│
├── styles/
│   └── globals.css

Step-by-Step Guide

1. Set Up the Next.js Project

npx create-next-app@latest chatgpt-clone --typescript --app
cd chatgpt-clone
npm install openai tailwindcss

Set up Tailwind:

npx tailwindcss init -p

Edit tailwind.config.js and add paths to your files.

2. Create the Chat UI

/app/page.tsx:

"use client"
import { useState } from "react"

export default function HomePage() {
  const [messages, setMessages] = useState([{ role: "system", content: "How can I help you today?" }])
  const [input, setInput] = useState("")

  async function sendMessage() {
    const newMessages = [...messages, { role: "user", content: input }]
    setMessages(newMessages)
    setInput("")

    const res = await fetch("/api/chat", {
      method: "POST",
      body: JSON.stringify({ messages: newMessages }),
    })

    const data = await res.json()
    setMessages([...newMessages, data.reply])
  }

  return (
    <main className="min-h-screen p-6 bg-gray-100">
      <div className="max-w-2xl mx-auto bg-white p-4 rounded shadow">
        <div className="space-y-2 mb-4 h-[400px] overflow-y-auto">
          {messages.map((m, i) => (
            <div key={i} className={`text-${m.role === "user" ? "right" : "left"}`}>
              <p className={`text-sm p-2 rounded ${m.role === "user" ? "bg-blue-100" : "bg-gray-200"}`}>
                {m.content}
              p>
            div>
          ))}
        div>
        <div className="flex gap-2">
          <input
            className="flex-1 border p-2 rounded"
            value={input}
            onChange={(e) => setInput(e.target.value)}
          />
          <button onClick={sendMessage} className="bg-blue-500 text-white px-4 rounded">Sendbutton>
        div>
      div>
    main>
  )
}

3. Connect to OpenAI API

/app/api/chat/route.ts:

import { OpenAI } from "openai"

const openai = new OpenAI({
  apiKey: process.env.OPENAI_API_KEY,
})

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

  const response = await openai.chat.completions.create({
    model: "gpt-3.5-turbo",
    messages,
  })

  const reply = response.choices[0].message
  return Response.json({ reply })
}

Make sure you add your API key in .env.local:

OPENAI_API_KEY=your_key_here

What I Learned

  • Rate limits are a real concern when working with OpenAI’s free tier.
  • Streaming responses are the future—instant feedback improves UX.
  • Next.js App Router is incredibly clean for separating logic.
  • It’s super easy to build SaaS-like tools using AI APIs.

What’s Next?

  • Add authentication using NextAuth.
  • Save chat history to Supabase or MongoDB.
  • Enable response streaming for real-time interaction.
  • Upgrade to GPT-4 for premium power users.

Final Thoughts

Building this ChatGPT clone was one of the most exciting and practical mini-projects I’ve done. If you’re a developer looking to experiment with AI, there’s no better way to start.

Everything I Build Is Available Here:

Let’s build cool stuff together!