DEV Community

Cover image for Ultimate Prisma ORM Guide With Mind Blowing Example Codes
Md. Maruf Rahman
Md. Maruf Rahman

Posted on • Edited on • Originally published at marufrahman.live

Ultimate Prisma ORM Guide With Mind Blowing Example Codes

Prisma changed how I think about database operations. Instead of writing raw SQL or dealing with complex ORM abstractions, Prisma gives you a type-safe, intuitive API that feels natural. It's like having autocomplete for your entire database schema, and TypeScript catches errors before they reach production.

I've worked with a lot of database tools over the years—raw SQL, Sequelize, TypeORM, you name it. Each had its strengths, but they all felt like they were fighting against me in some way. Then I discovered Prisma, and everything clicked. The type safety, the intuitive API, the automatic migrations—it all just makes sense.

Prisma is a next-generation ORM that gives you a type-safe database client. You define your schema in a simple, declarative format, and Prisma generates a fully-typed client for you. No more guessing what fields exist, no more runtime errors from typos, no more manual migration management.

What is Prisma ORM?

Prisma is a next-generation ORM (Object-Relational Mapping) tool for Node.js and TypeScript. It provides:

  • Type-safe database client - Full TypeScript support with autocomplete
  • Automatic migrations - Schema changes are tracked and applied automatically
  • Intuitive query API - Simple, chainable methods for all operations
  • Multi-database support - PostgreSQL, MySQL, SQLite, SQL Server, and MongoDB
  • Relationship handling - One-to-one, one-to-many, and many-to-many relationships
  • Raw SQL support - Run raw queries when needed with SQL injection protection

Installation and Setup

First, let's install Prisma:

npm install prisma @prisma/client --save-dev
npm install @prisma/adapter-pg pg  # For PostgreSQL
Enter fullscreen mode Exit fullscreen mode

Initialize Prisma in your project:

npx prisma init
Enter fullscreen mode Exit fullscreen mode

This creates a prisma directory with a schema.prisma file and adds a .env file for your database connection string.

Defining Your Schema

The schema file is where you define your database structure. Here's a complete example with all relationship types:

// prisma/schema.prisma

generator client {
  provider = "prisma-client"
  output   = "../generated/prisma"
}

datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

// User Model
model User {
  id               String          @id @default(uuid())
  age              Int
  name             String
  email            String          @unique
  role             Role            @default(BASIC)

  // One-to-Many: User has many Posts
  writtenPosts     Post[]          @relation("WrittenPosts")

  // One-to-One: User has one UserPreference
  userPreference   UserPreference? @relation(fields: [userPreferenceId], references: [id])
  userPreferenceId String?         @unique

  @@unique([age, name])  // Composite unique constraint
  @@index([email])       // Index on email
}

// One-to-One Relationship
model UserPreference {
  id           String  @id @default(uuid())
  emailUpdates Boolean
  user         User?   // One-to-one relationship with User
}

// One-to-Many Relationship
model Post {
  id            String   @id @default(uuid())
  title         String
  averageRating Float
  createdAt     DateTime @default(now())
  updatedAt     DateTime @updatedAt

  // Post belongs to User (author)
  author   User   @relation("WrittenPosts", fields: [authorId], references: [id])
  authorId String

  // Many-to-Many: Post has many Categories
  categories Category[]
}

// Many-to-Many Relationship
model Category {
  id    String @id @default(uuid())
  name  String @unique
  posts Post[]  // Many-to-many relationship with Post
}

enum Role {
  BASIC
  ADMIN
  USER
}
Enter fullscreen mode Exit fullscreen mode

After defining your schema, generate the Prisma Client and run migrations:

npx prisma generate
npx prisma migrate dev --name init
Enter fullscreen mode Exit fullscreen mode

Setting Up Prisma Client

Create a singleton instance of Prisma Client to avoid multiple connections in development:

// lib/prisma.ts
import "dotenv/config";
import { PrismaPg } from '@prisma/adapter-pg';
import { PrismaClient } from '../generated/prisma/client';

const connectionString = process.env.NEON_POSTGRES_DATABASE_URL!;

// Prevent multiple instances in development
const globalForPrisma = globalThis as unknown as {
  prisma: PrismaClient | undefined;
};

export const prisma =
  globalForPrisma.prisma ??
  new PrismaClient({
    adapter: new PrismaPg(pgPool),
    log: process.env.NODE_ENV === "development" ? ["query", "error", "warn"] : ["error"],
  });

if (process.env.NODE_ENV !== "production") globalForPrisma.prisma = prisma;
Enter fullscreen mode Exit fullscreen mode

Basic CRUD Operations

Create

// Create a single record
const user = await prisma.user.create({
  data: {
    name: "John Doe",
    email: "john@example.com",
    age: 30,
  },
});
Enter fullscreen mode Exit fullscreen mode

Read

// Find unique record
const user = await prisma.user.findUnique({
  where: { email: "john@example.com" },
});

// Find many with filters
const users = await prisma.user.findMany({
  where: { age: { gte: 18 } },
  orderBy: { createdAt: "desc" },
  take: 10,
});
Enter fullscreen mode Exit fullscreen mode

Update

// Update a single record
const user = await prisma.user.update({
  where: { id: "user-id" },
  data: { age: 31 },
});
Enter fullscreen mode Exit fullscreen mode

Delete

// Delete a single record
const user = await prisma.user.delete({
  where: { id: "user-id" },
});
Enter fullscreen mode Exit fullscreen mode

Best Practices

  1. Use Prisma Client singleton
  2. Define relationships properly
  3. Use transactions for complex operations
  4. Handle errors gracefully
  5. Use migrations for schema changes
  6. Leverage TypeScript types

📖 Read the Complete Guide

This is just a brief overview! The complete guide on my blog includes:

  • Relationships - One-to-one, one-to-many, many-to-many
  • Advanced Queries - Filtering, sorting, pagination
  • Transactions - Complex database operations
  • Migrations - Schema management
  • Raw SQL - When to use raw queries
  • Real-world examples from production applications

👉 Read the full article with all code examples here


What's your experience with Prisma? Share your tips in the comments! 🚀

For more backend guides, check out my blog covering Express.js, JWT Authentication, Sequelize, and more.

Top comments (0)