Leon

Prisma CRUD examples

Topics
NextjsPrisma
Published on 
21 Jan 2025

Prisma makes CRUD in Next.js simple, type-safe, and scalable. Define your schema, generate the client, and use Prisma’s API in your routes or server actions for all database operations.

prisma/schema.prisma
1generator client {
2  provider = "prisma-client-js"
3  output   = "../lib/generated/prisma"
4}
5
6datasource db {
7  provider  = "postgresql"
8  url       = env("DATABASE_URL")
9  directUrl = env("DIRECT_URL")
10}
11
12enum Role {
13  USER
14  ADMIN
15}
16
17model User {
18  id            String          @id @default(auto()) @map("_id") @db.ObjectId
19  email         String          @unique
20  name          String?
21  role          Role            @default(USER)
22  profileViews  Int             @default(0)
23  coinflips     Boolean[]
24  posts         Post[]
25  profile       ExtendedProfile?
26}
27
28model Post {
29  id        String   @id @default(auto()) @map("_id") @db.ObjectId
30  title     String
31  content   String?
32  published Boolean  @default(false)
33  author    User     @relation(fields: [authorId], references: [id])
34  authorId  String   @db.ObjectId
35}
36
37model ExtendedProfile {
38  id     String  @id @default(auto()) @map("_id") @db.ObjectId
39  bio    String?
40  user   User    @relation(fields: [userId], references: [id])
41  userId String  @unique @db.ObjectId
42}

Main CRUD Operations

1// Create
2const newUser = await prisma.user.create({
3  data: {
4    email: "test@example.com",
5    name: "Test User"
6  }
7});
8
9// Read
10// Find all users
11const allUsers = await prisma.user.findMany();
12
13// Find users with at least 100 profile views who've flipped "true"
14const activeUsers = await prisma.user.findMany({
15  where: {
16    profileViews: { gte: 100 },
17    coinflips: { has: true }  // Checks array contains true
18  }
19});
20
21// Find a unique user
22const existingUser = await prisma.user.findUnique({
23  where: { email: "test@example.com" }
24});
25
26// Update
27const updatedUser = await prisma.user.update({
28  where: { id: newUser.id },
29  data: { name: "Updated Name" }
30});
31
32// Upsert (Create or Update)
33const upsertedUser = await prisma.user.upsert({
34  where: { email: "test@example.com" },
35  create: {
36    email: "test@example.com",
37    name: "New User"
38  },
39  update: {
40    profileViews: 10
41  }
42});
43
44// Delete with related posts
45const deletePosts = prisma.post.deleteMany({
46  where: { authorId: newUser.id }
47});
48
49const deleteUser = prisma.user.delete({
50  where: { id: newUser.id }
51});
52
53await prisma.$transaction([deletePosts, deleteUser]);

await prisma.$transaction([deletePosts, deleteUser]) executes multiple database operations as a single atomic transaction using Prisma.

  1. Atomic Execution:
    All operations in the array either succeed together or fail together. If any operation fails, the entire transaction is rolled back, leaving the database in its original state.
  2. Order Matters:
    Operations run sequentially in the order they appear in the array. For example:
1// Delete posts first, THEN delete the user
2await prisma.$transaction([deletePosts, deleteUser]);

If you reverse the order ([deleteUser, deletePosts]), deleting the user first would cause foreign key errors in the posts table.

Query Order: Always delete dependent records (e.g., posts) before the parent record (e.g., user).