Prisma ORM: Full Guide with Relations, Queries, Filters, and Schema Design


Prisma = modern ORM for Node.js/TypeScript.
Works with PostgreSQL, MySQL, SQLite, MongoDB, CockroachDB.
In the context of databases, ORM stands for Object-Relational Mapping. It's a programming technique that creates a "bridge" between object-oriented programming (OOP) languages and relational databases.
1. generator
and datasource
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
generator
tells Prisma how to generate the clientdatasource
tells Prisma which DB to use and how to connect
2. Schema Management: Migrate vs Push
Command | Description |
prisma migrate dev | Creates SQL migrations and updates the DB. Use in production or version-controlled work. |
prisma db push | Updates the database directly without migration files. Use in prototyping. |
3. Model Attributes
model User {
id Int @id @default(autoincrement())
uuid String @default(uuid()) @unique
email String @unique
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
role Role @default(USER)
}
Attribute | Purpose |
@id | Primary key |
@default(value) | Set default value (e.g., uuid() , now() , autoincrement() ) |
@unique | Enforces column uniqueness |
@updatedAt | Automatically updates field on any row update |
@map("db_column_name") | Maps to a different DB column name |
@ignore | Tells Prisma to ignore this field (not mapped to DB) |
4. Global Constraints & Indexing
model Product {
sku String
warehouse String
@@unique([sku, warehouse])
@@index([warehouse])
}
Constraint | Description |
@@unique([...]) | Enforces unique combo of multiple fields |
@@index([...]) | Creates a DB index to speed up queries |
5. Enums
enum Role {
ADMIN
USER
GUEST
}
Used to limit a field to specific values.
6. Relationships
One-to-One
model User {
id Int @id @default(autoincrement())
profile Profile?
}
model Profile {
id Int @id @default(autoincrement())
userId Int @unique
user User @relation(fields: [userId], references: [id])
}
One-to-Many
model User {
id Int @id @default(autoincrement())
posts Post[]
}
model Post {
id Int @id @default(autoincrement())
userId Int
user User @relation(fields: [userId], references: [id])
}
Many-to-Many (implicit)
model Student {
id Int @id @default(autoincrement())
classes Class[]
}
model Class {
id Int @id @default(autoincrement())
students Student[]
}
7. Create with Nested select
and include
await prisma.user.create({
data: {
name: 'Alice',
profile: {
create: {
bio: 'Developer',
}
}
},
include: {
profile: true
}
})
Use select
to pick fields, include
to include related models.
8. Read Queries
findUnique
, findFirst
, findMany
prisma.user.findUnique({ where: { id: 1 } })
prisma.user.findFirst({ where: { isAdmin: true } })
prisma.user.findMany({
where: {
name: {
startsWith: "A",
contains: "b",
notIn: ["Abhi", "Dev"],
},
age: {
gt: 18,
},
},
orderBy: {
createdAt: 'desc'
},
skip: 2,
take: 5
})
Filtering
where: {
name: { equals: "Alice", not: "Bob" },
id: { in: [1, 2], notIn: [3] },
email: { endsWith: "@gmail.com", contains: "test" },
}
9. Logical Operators
where: {
AND: [
{ name: { startsWith: "A" } },
{ isAdmin: true }
],
OR: [
{ email: { endsWith: "@gmail.com" } },
{ email: { endsWith: "@yahoo.com" } }
],
NOT: {
name: "Blocked"
}
}
10. Filtering by Relations
prisma.user.findMany({
where: {
preferences: {
emailUpdates: true
}
}
})
With quantifiers:
where: {
posts: {
some: { published: true },
none: { archived: true },
every: { authorId: 1 }
}
}
Nested relations:
where: {
author: {
is: { role: 'ADMIN' }
}
}
11. Update Operations
update
& updateMany
await prisma.user.update({
where: { id: 1 },
data: { name: "New Name" }
})
await prisma.user.updateMany({
where: { isAdmin: false },
data: { isAdmin: true }
})
Arithmetic
await prisma.product.update({
where: { id: 1 },
data: {
stock: { decrement: 1 },
price: { multiply: 1.1 }
}
})
12. Connect & Disconnect Relationships
await prisma.post.update({
where: { id: 1 },
data: {
author: {
connect: { id: 2 }
}
}
})
await prisma.post.update({
where: { id: 1 },
data: {
author: {
disconnect: true
}
}
})
13. Other Useful Features
@map
model User {
fullName String @map("full_name")
}
Maps Prisma field to actual DB column.
@ignore
model User {
tempField String @ignore
}
Tells Prisma to ignore this field (not generated in client).
Summary Table
Category | Features |
Basic Attributes | @id , @default , @unique , @updatedAt , @map , @ignore |
Global Constraints | @@unique , @@index |
Relations | @relation , connect , disconnect , is , isNot , some , none , every |
Queries | findUnique , findFirst , findMany , create , update , delete |
Filters | equals , not , in , notIn , contains , startsWith , endsWith , lt , gt , lte , gte |
Logical Conditions | AND , OR , NOT |
Pagination | take , skip |
Math Updates | increment , decrement , multiply , divide |
Nested Fields | select , include , nested create/connect |
Thanks to Web Dev Simplified- Prisma
Subscribe to my newsletter
Read articles from Abheeshta P directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Abheeshta P
Abheeshta P
I am a Full-stack dev turning ideas into sleek, functional experiences ๐. I am passionate about AI, intuitive UI/UX, and crafting user-friendly platforms . I am always curious โ from building websites to diving into machine learning and under the hood workings โจ. Next.js, Node.js, MongoDB, and Tailwind are my daily tools. I am here to share dev experiments, lessons learned, and the occasional late-night code breakthroughs. Always evolving, always building.