Next.js 14 telah menjadi standar de‑facto untuk aplikasi React modern. Tutorial ini menjelaskan langkah demi langkah cara meng‑install, meng‑konfigurasi, dan membangun fitur AI dengan OpenAI API, lengkap dengan best practice untuk performance dan security.

1. Persiapan Lingkungan

Pastikan Anda memiliki Node.js versi 20.12+ dan npm atau pnpm terbaru. Verifikasi dengan:

node -v
npm -v

Jika belum terpasang, unduh dari nodejs.org atau gunakan nvm untuk mengelola versi.

2. Membuat Projekt Next.js 14 dengan TypeScript

npx create-next-app@latest my-next14-app \
  --ts \
  --eslint \
  --experimental-app-router
cd my-next14-app

Perintah di atas menghasilkan struktur folder baru dengan app/ directory (App Router) dan konfigurasi TypeScript standar.

3. Instalasi Dependensi Penting

# Manajemen paket: pilih npm atau pnpm
npm i dotenv openai@4 zod
# atau
pnpm add dotenv openai@4 zod

dotenv – memuat variabel lingkungan secara aman.
openai@4 – SDK resmi OpenAI yang mendukung streaming.
zod – validasi schema tipe‑safe untuk request API.

4. Konfigurasi Variables Lingkungan

Buat file .env.local di root project dan tambahkan:

NEXT_PUBLIC_OPENAI_MODEL=gpt-4o-mini
OPENAI_API_KEY=sk-**************

Gunakan NEXT_PUBLIC_ hanya untuk nilai yang memang boleh di‑expose ke client (model name). Jangan pernah commit file ini ke repo.

5. Membuat API Route untuk OpenAI

Di dalam folder app/api/chat/route.ts buat endpoint yang akan menerima prompt, memanggil OpenAI, dan mengembalikan streaming response.

import { NextResponse } from 'next/server';
import { OpenAI } from 'openai';
import { z } from 'zod';
import dotenv from 'dotenv';

dotenv.config();

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

const BodySchema = z.object({
  prompt: z.string().min(1),
});

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

    const completion = await openai.chat.completions.create({
      model: process.env.NEXT_PUBLIC_OPENAI_MODEL,
      messages: [{ role: 'user', content: prompt }],
      stream: true,
    });

    const encoder = new TextEncoder();
    const stream = new ReadableStream({
      async start(controller) {
        for await (const chunk of completion) {
          const content = chunk.choices[0].delta?.content || '';
          controller.enqueue(encoder.encode(content));
        }
        controller.close();
      },
    });

    return new NextResponse(stream, {
      headers: { 'Content-Type': 'text/event-stream' },
    });
  } catch (err) {
    console.error(err);
    return NextResponse.json({ error: 'Invalid request' }, { status: 400 });
  }
}

Endpoint ini sudah mengikuti best practice: validasi schema, penanganan error, dan streaming untuk UX yang responsif.

6. Membuat UI Chat di Front‑End

Tambahkan komponen ChatBox.tsx di app/components/ChatBox.tsx:

"use client";
import { useState, useRef, FormEvent } from 'react';

export default function ChatBox() {
  const [messages, setMessages] = useState<string[]>([]);
  const [input, setInput] = useState('');
  const textareaRef = useRef<HTMLTextAreaElement>(null);

  const handleSubmit = async (e: FormEvent) => {
    e.preventDefault();
    if (!input.trim()) return;
    setMessages(prev => [...prev, `You: ${input}`]);
    const response = await fetch('/api/chat', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ prompt: input }),
    });
    const reader = response.body?.getReader();
    const decoder = new TextDecoder();
    let done = false;
    let aiReply = '';
    while (!done && reader) {
      const { value, done: doneReading } = await reader.read();
      done = doneReading;
      if (value) {
        aiReply += decoder.decode(value);
        setMessages(prev => [...prev.slice(0, -1), `AI: ${aiReply}`]);
      }
    }
    setInput('');
    textareaRef.current?.focus();
  };

  return (
    
{messages.map((msg, i) => (

{msg}

))}