Prisma adalah toolkit ORM modern untuk lingkungan JavaScript dan TypeScript yang menekankan keselamatan tipe dan pengalaman pengembangan. Dengan Prisma, model data ditulis pada berkas schema.prisma, dari sana Prisma menghasilkan client yang aman tipe yang bisa dipanggil langsung dari kode aplikasi Anda. Migrasi skema dikurasi oleh Prisma Migrate, sementara inspeksi data harian dipermudah oleh Prisma Studio.
Di lingkungan produksi, Prisma membantu menstandarkan akses data, menyederhanakan query kompleks, dan mengurangi kesalahan runtime. Panduan ini bersifat praktis: Anda akan membuat proyek, menyusun skema, menjalankan migrasi, menulis query, melakukan transaksi, hingga menyiapkan praktik terbaik untuk produksi.
Apa Itu Prisma
Prisma adalah ORM yang berfokus pada keselarasan antara skema dan kode. Anda menuliskan model domain pada schema.prisma, men-generate client, lalu memanggilnya di kode aplikasi menggunakan API yang konsisten. Pendekatan ini meminimalkan mismatch antara struktur tabel dan type di aplikasi.
- Prisma Client: klien kueri yang aman tipe, dihasilkan dari skema.
- Prisma Migrate: alat migrasi terkelola, menyusun perubahan skema ke dalam migration bermetadatakan.
- Prisma Studio: antarmuka grafis untuk melihat dan mengedit data selama pengembangan.
Fitur Utama
- Type-safe penuh pada TypeScript, mengurangi kesalahan query di runtime.
- Intellisense dan auto-complete saat menulis query yang kompleks.
- Migrate dengan histori yang jelas, memudahkan audit.
- Relasi yang ekspresif: satu lawan banyak, banyak lawan banyak, dengan include / select yang konsisten.
- Kompatibel dengan PostgreSQL, MySQL, MariaDB, SQLite, SQL Server, MongoDB, dan lain-lain yang didukung.
Menyiapkan Proyek
Bagian ini menyiapkan proyek Node dan TypeScript dengan Prisma. Pastikan Node dan paket pengelola tersedia.
mkdir prisma-app
cd prisma-app
npm init -y
npm install prisma @prisma/client typescript ts-node --save-dev
npx prisma init --datasource-provider postgresqlPerintah di atas membuat folder prisma dan berkas .env. Isi variabel koneksi basis data dengan aman (hindari menaruh kredensial pada artikel publik).
# .env
DATABASE_URL="postgresql://USER:PASS@HOST:PORT/DBNAME?schema=public"Skema Dasar
Berikut contoh model sederhana yang memuat pengguna, tulisan, dan kategori. Gunakan nama indeks yang jelas dan relasi dua arah agar navigasi data mudah.
prisma/schema.prismagenerator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
model User {
id String @id @default(cuid())
email String @unique
name String
posts Post[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model Post {
id String @id @default(cuid())
title String
content String?
published Boolean @default(false)
author User @relation(fields: [authorId], references: [id])
authorId String
categories Category[] @relation("PostCategories")
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([authorId], map: "idx_post_author")
}
model Category {
id String @id @default(cuid())
name String @unique
posts Post[] @relation("PostCategories")
}Migrasi Skema
Migrasi menyinkronkan model dengan database. Gunakan nama migrasi yang deskriptif. Hindari perubahan besar tanpa uji di lingkungan pengujian.
npx prisma migrate dev --name init_schema
# Lihat hasil:
npx prisma migrate statusMenggunakan Prisma Client
Setelah migrasi, Prisma Client siap digunakan. Contoh di bawah memakai TypeScript murni dengan eksekusi via ts-node.
src/app.tsimport { PrismaClient } from "@prisma/client";
const prisma = new PrismaClient();
async function main() {
// Buat user
const alice = await prisma.user.create({
data: { email: "alice@example.com", name: "Alice" },
});
// Buat kategori
const tech = await prisma.category.upsert({
where: { name: "Teknologi" },
update: {},
create: { name: "Teknologi" },
});
// Buat post terhubung user + kategori
const post = await prisma.post.create({
data: {
title: "Mengenal Prisma",
content: "Prisma memudahkan akses data aman tipe.",
author: { connect: { id: alice.id } },
categories: { connect: [{ id: tech.id }] },
published: true,
},
include: { author: true, categories: true },
});
console.log("Post baru:", post);
// Baca daftar post terbaru
const recent = await prisma.post.findMany({
where: { published: true },
orderBy: { createdAt: "desc" },
take: 10
});
console.log("Post terbaru:", recent.map(p => ({ id: p.id, title: p.title })));
}
main()
.catch((e) => { console.error(e); process.exit(1); })
.finally(async () => { await prisma.$disconnect(); });npx ts-node src/app.tsRelasi, Paginasi, dan Filter
Prisma menyediakan pola kueri yang konsisten untuk relasi, paginasi, dan penyaringan. Gunakan include saat memerlukan relasi, serta select untuk efisiensi data.
/* Ambil post beserta author dan kategori */
const posts = await prisma.post.findMany({
include: {
author: { select: { id: true, email: true, name: true } },
categories: true
},
where: {
published: true,
title: { contains: "Prisma", mode: "insensitive" }
},
orderBy: [{ createdAt: "desc" }],
skip: 0,
take: 20
});/* Paginasi berbasis cursor */
const firstPage = await prisma.post.findMany({
take: 10,
orderBy: { createdAt: "desc" }
});
const cursor = firstPage.at(-1)?.id;
const nextPage = await prisma.post.findMany({
take: 10,
skip: 1,
cursor: { id: cursor },
orderBy: { createdAt: "desc" }
});Transaksi dan Konsistensi
Transaksi memastikan konsistensi ketika beberapa perubahan harus berhasil seluruhnya. Prisma menyediakan $transaction untuk menjalankan beberapa operasi sekaligus.
await prisma.$transaction(async (tx) => {
const u = await tx.user.create({
data: { email: "bob@example.com", name: "Bob" }
});
await tx.post.create({
data: {
title: "Tulisan Perdana Bob",
authorId: u.id,
published: false
}
});
});Indeks dan Kinerja
Indeks yang tepat meningkatkan kinerja pencarian. Pada model, gunakan @@index atau @@unique sesuai kebutuhan. Untuk pola pencarian gabungan, pertimbangkan indeks komposit.
model Post {
id String @id @default(cuid())
title String
published Boolean @default(false)
createdAt DateTime @default(now())
@@index([published, createdAt], map: "idx_post_published_created")
}Seed Data
Gunakan seeding untuk pengisian awal. Prisma mendukung skrip seed pada package.json. Pastikan data seed tidak mengandung kredensial nyata.
# package.json (bagian scripts)
"prisma": {
"seed": "ts-node prisma/seed.ts"
}prisma/seed.tsimport { PrismaClient } from "@prisma/client";
const prisma = new PrismaClient();
async function main() {
const names = ["Teknologi","Desain","Pendidikan"];
for (const n of names) {
await prisma.category.upsert({
where: { name: n },
update: {},
create: { name: n }
});
}
}
main().finally(() => prisma.$disconnect());Prisma Studio
Prisma Studio memudahkan inspeksi dan edit data lokal selama pengembangan. Jangan mengeksposnya ke publik.
npx prisma studioCatatan Deployment dan Pooling
Pada lingkungan produksi, perhatikan pooling koneksi. Untuk beban tinggi atau arsitektur tanpa proses panjang, letakkan connection pooler seperti pgbouncer di depan PostgreSQL. Atur variabel lingkungan dan jumlah pool sesuai kapasitas.
# .env contoh (Postgres lewat pgbouncer)
DATABASE_URL="postgresql://USER:PASS@PGBOUNCER_HOST:6432/DBNAME?schema=public&pgbouncer=true"
PRISMA_CLIENT_ENGINE_TYPE="binary"Integrasi Aplikasi
Prisma bekerja baik dengan Express, Fastify, Next, Remix, atau kerangka kerja lain. Prinsip utamanya: instansiasi Prisma Client satu kali dan pakai ulang sepanjang siklus hidup proses.
/* Express contoh singkat */
import express from "express";
import { PrismaClient } from "@prisma/client";
const prisma = new PrismaClient();
const app = express();
app.get("/posts", async (req, res) => {
const rows = await prisma.post.findMany({ where: { published: true } });
res.json(rows);
});
app.listen(3000, () => console.log("Server siap"));Perbandingan Prisma dengan ORM Lain
| Aspek | Prisma | TypeORM | Sequelize |
|---|---|---|---|
| Keselamatan Tipe | Kuat, client dihasilkan dari skema | Baik, bergantung dekorator | Terbatas pada tipe runtime |
| Migrasi | Terintegrasi, histori jelas | Ada, butuh ketelitian | Ada, variasi praktik |
| API Query | Deklaratif, konsisten | Dekorator + repositori | Model berbasis instance |
| Pengalaman Dev | Auto-complete menyeluruh | Lengkap namun verbose | Luas ekosistem, gaya beragam |
| Dukungan DB | Postgres, MySQL, MariaDB, SQLite, SQL Server, Mongo | Relasional umum | Relasional umum |
Keamanan dan Praktik Terbaik
- Simpan kredensial pada variabel lingkungan atau pengelola rahasia. Jangan menaruh
DATABASE_URLdi sumber terbuka. - Batasi hak pengguna basis data sesuai prinsip hak minimum.
- Audit migrasi sebelum penerapan, terutama operasi destruktif.
- Aktifkan logging di level yang tepat dan sanitasi data sensitif dari log.
- Uji konsistensi dengan unit test pada layer data.
Troubleshooting
- Koneksi ditolak — Periksa
DATABASE_URL, keamanan jaringan, dan kebijakan IP yang diizinkan. - Migrasi gagal — Tinjau perbedaan skema, cek
prisma/migrations, dan jalankan ulang pada salinan data. - Timeout — Evaluasi indeks, optimalkan query, gunakan pooling, atau sesuaikan timeout pada sisi server dan aplikasi.
- Deadlock — Gunakan transaksi yang lebih kecil, urutan penulisan konsisten, dan tangani retry secara hati-hati.
Kesimpulan
Prisma menyederhanakan akses data tanpa mengorbankan kekuatan SQL. Dengan skema yang eksplisit, migrasi yang terkelola, serta client yang aman tipe, tim dapat bergerak cepat dan percaya diri. Terapkan praktik produksi seperti pooling, pengujian, dan audit migrasi agar fondasi data tetap kokoh seiring pertumbuhan aplikasi.
Sumber/Referensi
- https://www.prisma.io/docs
- https://www.prisma.io/docs/orm/prisma-client
- https://www.prisma.io/docs/orm/prisma-migrate
- https://www.prisma.io/studio
- https://www.prisma.io/docs/orm/prisma-client/observability-and-logging
- https://www.prisma.io/docs/orm/prisma-client/setup-and-configuration/databases-connections#connection-pooling

