Dalam artikel ini, kita akan membuat aplikasi Next.js dari awal dengan Prisma sebagai ORM, Socket.io untuk real-time chat, dan tanpa backend terpisah.
Semua dijalankan dalam satu proses menggunakan npm run dev.
1. Membuat Proyek Next.js
Pertama, buat proyek baru menggunakan Next.js:
npx create-next-app@latest my-app --ts --tailwind
cd my-app
Jalankan proyek:
npm run dev
Buka http://localhost:3000 untuk melihat tampilan default Next.js.
2. Setup Prisma di Next.js
Install Prisma dan klien database:
npm install @prisma/client @prisma/cli
npx prisma init
Buka file prisma/schema.prisma dan ubah skema sebagai berikut:
model User {
  id    String @id @default(uuid())
  name  String
  email String @unique
}
model Message {
  id        String   @id @default(uuid())
  senderId  String
  recipientId String
  content   String
  createdAt DateTime @default(now())
  sender    User @relation(fields: [senderId], references: [id])
  recipient User @relation(fields: [recipientId], references: [id])
}
Jalankan migrasi:
npx prisma migrate dev --name init
Buat file /lib/prisma.ts untuk mencegah banyak instance Prisma:
import { PrismaClient } from "@prisma/client";
const globalForPrisma = global as unknown as { prisma?: PrismaClient };
export const prisma = globalForPrisma.prisma ?? new PrismaClient();
if (process.env.NODE_ENV !== "production") globalForPrisma.prisma = prisma;
Buat fungsi database di /lib/messages.ts:
import { prisma } from "./prisma";
export const sendMessage = async (senderId: string, recipientId: string, content: string) => {
  return prisma.message.create({ data: { senderId, recipientId, content } });
};
export const getMessages = async (userId: string) => {
  return prisma.message.findMany({
    where: { OR: [{ senderId: userId }, { recipientId: userId }] },
    orderBy: { createdAt: "asc" },
  });
};
3. Setup Socket.io di Next.js
Install Socket.io:
npm install socket.io socket.io-client
Buat file /lib/socket.ts untuk menangani koneksi Socket.io:
import { Server as HttpServer } from "http";
import { Server as SocketIOServer } from "socket.io";
import { sendMessage } from "./messages";
let io: SocketIOServer | null = null;
export const initSocket = (server: HttpServer) => {
  if (!io) {
    io = new SocketIOServer(server, { cors: { origin: "*" } });
    io.on("connection", (socket) => {
      console.log("User connected:", socket.id);
      socket.on("sendMessage", async (data) => {
        const message = await sendMessage(data.senderId, data.recipientId, data.content);
        io?.emit("newMessage", message);
      });
      socket.on("disconnect", () => console.log("User disconnected:", socket.id));
    });
  }
};
Tambahkan server.ts untuk menjalankan Next.js dan Socket.io dalam satu proses:
import { createServer } from "http";
import { initSocket } from "./lib/socket";
import next from "next";
const dev = process.env.NODE_ENV !== "production";
const app = next({ dev });
const handle = app.getRequestHandler();
app.prepare().then(() => {
  const server = createServer((req, res) => handle(req, res));
  initSocket(server);
  server.listen(3000, () => {
    console.log("Server running on http://localhost:3000");
  });
});
Tambahkan ke package.json:
"scripts": {
  "dev": "node server.ts"
}
4. Menggunakan Socket.io di Frontend
Buat hook /lib/useChat.ts:
import { useEffect, useState } from "react";
import { io } from "socket.io-client";
const socket = io("http://localhost:3000");
export const useChat = () => {
  const [messages, setMessages] = useState([]);
  useEffect(() => {
    socket.on("newMessage", (message) => {
      setMessages((prev) => [...prev, message]);
    });
    return () => {
      socket.off("newMessage");
    };
  }, []);
  const sendMessage = (senderId: string, recipientId: string, content: string) => {
    socket.emit("sendMessage", { senderId, recipientId, content });
  };
  return { messages, sendMessage };
};
5. Membuat UI Chat
Di dalam components/Chat.tsx:
"use client";
import { useChat } from "@/lib/useChat";
import { useState } from "react";
export const Chat = ({ userId }: { userId: string }) => {
  const { messages, sendMessage } = useChat();
  const [content, setContent] = useState("");
  const handleSend = () => {
    sendMessage(userId, "recipient-id", content);
    setContent("");
  };
  return (
    <div className="p-4 border border-gray-300 rounded-md w-96">
      <div className="h-60 overflow-y-auto border-b border-gray-300 mb-2 p-2">
        {messages.map((msg, index) => (
          <div key={index} className="p-2 bg-gray-100 rounded-md my-1">
            {msg.content}
          </div>
        ))}
      </div>
      <div className="flex gap-2">
        <input
          className="flex-1 p-2 border rounded-md"
          value={content}
          onChange={(e) => setContent(e.target.value)}
        />
        <button className="bg-blue-500 text-white px-4 py-2 rounded-md" onClick={handleSend}>
          Send
        </button>
      </div>
    </div>
  );
};
Kesimpulan
Dengan pendekatan ini:
- Next.js digunakan sebagai frontend dan backend dalam satu proses.
 - Prisma dikelola langsung tanpa API Routes.
 - Socket.io berjalan dalam server Next.js.
 - Chat real-time bisa langsung digunakan dengan 
npm run dev. 
Pendekatan ini sangat cocok untuk proyek sederhana tanpa backend terpisah.
    
Top comments (0)