Aller au contenu

Prisma Cheat Sheet

Overview

Prisma is a next-generation ORM for Node.js and TypeScript that consists of three main tools: Prisma Client (auto-generated type-safe query builder), Prisma Migrate (declarative migration system), and Prisma Studio (visual database browser). It replaces traditional ORMs with a declarative schema approach where you define your data model in a .prisma file, and Prisma generates a fully typed client tailored to your schema.

Prisma supports PostgreSQL, MySQL, SQLite, SQL Server, MongoDB, and CockroachDB. Its type-safe client catches errors at compile time rather than runtime, and its query engine is written in Rust for optimal performance. Prisma is widely adopted in the JavaScript/TypeScript ecosystem, particularly with frameworks like Next.js, Remix, and NestJS, and excels at providing a productive, type-safe database experience.

Installation

Setup

# Initialize in existing project
npm install prisma --save-dev
npx prisma init

# With specific database
npx prisma init --datasource-provider postgresql
npx prisma init --datasource-provider mysql
npx prisma init --datasource-provider sqlite

# Install Prisma Client
npm install @prisma/client

Project Files

FileDescription
prisma/schema.prismaData model and configuration
prisma/migrations/Migration history
.envDatabase connection string

Schema Definition

Basic Schema

// prisma/schema.prisma
generator client {
  provider = "prisma-client-js"
}

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

enum Role {
  USER
  ADMIN
  MODERATOR
}

model User {
  id        Int       @id @default(autoincrement())
  email     String    @unique
  name      String?
  role      Role      @default(USER)
  active    Boolean   @default(true)
  age       Int?
  posts     Post[]
  comments  Comment[]
  profile   Profile?
  createdAt DateTime  @default(now())
  updatedAt DateTime  @updatedAt

  @@index([email])
  @@map("users")
}

model Post {
  id        Int       @id @default(autoincrement())
  title     String    @db.VarChar(255)
  body      String
  published Boolean   @default(false)
  author    User      @relation(fields: [authorId], references: [id], onDelete: Cascade)
  authorId  Int
  comments  Comment[]
  tags      Tag[]
  createdAt DateTime  @default(now())
  updatedAt DateTime  @updatedAt

  @@index([authorId])
  @@map("posts")
}

model Comment {
  id        Int      @id @default(autoincrement())
  content   String
  post      Post     @relation(fields: [postId], references: [id], onDelete: Cascade)
  postId    Int
  author    User     @relation(fields: [authorId], references: [id])
  authorId  Int
  createdAt DateTime @default(now())

  @@map("comments")
}

model Profile {
  id     Int    @id @default(autoincrement())
  bio    String?
  avatar String?
  user   User   @relation(fields: [userId], references: [id])
  userId Int    @unique

  @@map("profiles")
}

model Tag {
  id    Int    @id @default(autoincrement())
  name  String @unique
  posts Post[]
}

Field Attributes

AttributeDescriptionExample
@idPrimary keyid Int @id
@default()Default value@default(autoincrement())
@uniqueUnique constraintemail String @unique
@relationForeign key relation@relation(fields: [userId], references: [id])
@updatedAtAuto-update timestampupdatedAt DateTime @updatedAt
@map()Custom column name@map("user_name")
@@map()Custom table name@@map("users")
@@index()Database index@@index([email, name])
@@unique()Compound unique@@unique([email, name])
@db.VarChar()Native type@db.VarChar(255)

CLI Commands

CommandDescription
npx prisma generateGenerate Prisma Client
npx prisma migrate devCreate and apply migration (dev)
npx prisma migrate dev --name initNamed migration
npx prisma migrate deployApply migrations (production)
npx prisma migrate resetReset database (drop + migrate + seed)
npx prisma db pushPush schema without migration
npx prisma db pullIntrospect existing database
npx prisma db seedRun seed script
npx prisma studioOpen visual database browser
npx prisma formatFormat schema file
npx prisma validateValidate schema

CRUD Operations

Client Setup

import { PrismaClient } from '@prisma/client';

const prisma = new PrismaClient({
  log: ['query', 'info', 'warn', 'error'],
});

// Singleton pattern (for Next.js etc.)
const globalForPrisma = globalThis as unknown as { prisma: PrismaClient };
export const prisma = globalForPrisma.prisma || new PrismaClient();
if (process.env.NODE_ENV !== 'production') globalForPrisma.prisma = prisma;

Create

// Single create
const user = await prisma.user.create({
  data: {
    name: 'Alice',
    email: 'alice@example.com',
    role: 'USER',
  },
});

// Create with relations
const userWithPost = await prisma.user.create({
  data: {
    name: 'Bob',
    email: 'bob@example.com',
    posts: {
      create: [
        { title: 'First Post', body: 'Content here' },
        { title: 'Second Post', body: 'More content' },
      ],
    },
    profile: {
      create: { bio: 'Hello world' },
    },
  },
  include: {
    posts: true,
    profile: true,
  },
});

// Create many
const count = await prisma.user.createMany({
  data: [
    { name: 'User 1', email: 'u1@example.com' },
    { name: 'User 2', email: 'u2@example.com' },
  ],
  skipDuplicates: true,
});

Read

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

// Find first
const admin = await prisma.user.findFirst({
  where: { role: 'ADMIN' },
  orderBy: { createdAt: 'desc' },
});

// Find many with filtering
const users = await prisma.user.findMany({
  where: {
    AND: [
      { active: true },
      { OR: [
        { role: 'ADMIN' },
        { age: { gte: 18 } },
      ]},
    ],
    name: { contains: 'alice', mode: 'insensitive' },
    email: { endsWith: '@example.com' },
  },
  select: {
    id: true,
    name: true,
    email: true,
    _count: { select: { posts: true } },
  },
  orderBy: { createdAt: 'desc' },
  take: 10,
  skip: 0,
});

// Include relations
const userWithPosts = await prisma.user.findUnique({
  where: { id: 1 },
  include: {
    posts: {
      where: { published: true },
      orderBy: { createdAt: 'desc' },
      take: 5,
      include: { comments: true },
    },
    profile: true,
  },
});

// Aggregation
const stats = await prisma.user.aggregate({
  _count: true,
  _avg: { age: true },
  _min: { age: true },
  _max: { age: true },
  where: { active: true },
});

// Group by
const grouped = await prisma.user.groupBy({
  by: ['role'],
  _count: true,
  _avg: { age: true },
  having: { age: { _avg: { gt: 25 } } },
});

Update

// Update one
const updated = await prisma.user.update({
  where: { id: 1 },
  data: {
    name: 'Alice Smith',
    age: { increment: 1 },
  },
});

// Update many
const result = await prisma.user.updateMany({
  where: { active: false },
  data: { role: 'USER' },
});

// Upsert
const user = await prisma.user.upsert({
  where: { email: 'alice@example.com' },
  update: { name: 'Alice Updated' },
  create: { name: 'Alice', email: 'alice@example.com' },
});

Delete

// Delete one
const deleted = await prisma.user.delete({
  where: { id: 1 },
});

// Delete many
const result = await prisma.user.deleteMany({
  where: { active: false },
});

Configuration

Environment Variables

# .env
DATABASE_URL="postgresql://user:password@localhost:5432/mydb?schema=public"

Seed Script

// prisma/seed.ts
import { PrismaClient } from '@prisma/client';

const prisma = new PrismaClient();

async function main() {
  await prisma.user.upsert({
    where: { email: 'admin@example.com' },
    update: {},
    create: {
      email: 'admin@example.com',
      name: 'Admin',
      role: 'ADMIN',
    },
  });
}

main()
  .then(() => prisma.$disconnect())
  .catch((e) => {
    console.error(e);
    prisma.$disconnect();
    process.exit(1);
  });
// package.json
{
  "prisma": {
    "seed": "tsx prisma/seed.ts"
  }
}

Advanced Usage

Transactions

// Interactive transaction
const result = await prisma.$transaction(async (tx) => {
  const user = await tx.user.create({
    data: { name: 'Alice', email: 'alice@example.com' },
  });

  const post = await tx.post.create({
    data: { title: 'First Post', body: 'Content', authorId: user.id },
  });

  return { user, post };
});

// Sequential transaction
const [user, posts] = await prisma.$transaction([
  prisma.user.findUnique({ where: { id: 1 } }),
  prisma.post.findMany({ where: { authorId: 1 } }),
]);

Raw SQL

// Raw query
const users = await prisma.$queryRaw`
  SELECT * FROM users WHERE age > ${18} ORDER BY name
`;

// Raw execute
const result = await prisma.$executeRaw`
  UPDATE users SET active = false WHERE last_login < ${cutoffDate}
`;

// Tagged template for type safety
import { Prisma } from '@prisma/client';

const email = 'alice@example.com';
const result = await prisma.$queryRaw(
  Prisma.sql`SELECT * FROM users WHERE email = ${email}`
);

Middleware

prisma.$use(async (params, next) => {
  const before = Date.now();
  const result = await next(params);
  const after = Date.now();
  console.log(`${params.model}.${params.action} took ${after - before}ms`);
  return result;
});

// Soft delete middleware
prisma.$use(async (params, next) => {
  if (params.model === 'User') {
    if (params.action === 'delete') {
      params.action = 'update';
      params.args.data = { deletedAt: new Date() };
    }
    if (params.action === 'findMany') {
      params.args.where = { ...params.args.where, deletedAt: null };
    }
  }
  return next(params);
});

Troubleshooting

ProblemSolution
Types not updatingRun npx prisma generate after schema changes
P2002: Unique constraint failedCheck for duplicate values; use upsert
P2025: Record not foundUse findFirst instead of findUnique or check record exists
Slow queriesAdd @@index to schema; use select to limit fields
Connection pool exhaustionSet connection_limit in URL; use singleton pattern
Migration driftRun npx prisma migrate diff; reset dev DB if needed
Prisma Studio won’t openCheck DATABASE_URL is correct; ensure DB is accessible
TypeScript errors after updateDelete node_modules/.prisma and regenerate