Part 4: CRUD Operations and Prisma Client Fundamentals

Introduction

Now that we have our schema designed and migrations in place, it's time to interact with our database. In this part, I'll walk you through the CRUD (Create, Read, Update, Delete) operations using Prisma Clientβ€”the type-safe database client that Prisma generates from your schema.

I remember the satisfaction when I first replaced hundreds of lines of raw SQL queries with clean, type-safe Prisma operations in a microservices project. Not only did my code become more readable, but TypeScript caught errors before they reached production.

Understanding Prisma Client

What is Prisma Client?

Prisma Client is an auto-generated, type-safe database client. Every time you run npx prisma migrate dev or npx prisma generate, Prisma reads your schema and generates TypeScript types and methods.

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

const prisma = new PrismaClient();

// TypeScript knows exactly what fields exist
const user = await prisma.user.findUnique({
  where: { email: '[email protected]' }
});

// βœ… TypeScript autocomplete works
console.log(user?.name);

// ❌ TypeScript error - 'emial' doesn't exist
console.log(user?.emial);  // Error: Property 'emial' does not exist

Setting Up Prisma Client

Here's how I structure Prisma Client in my applications:

Now import it anywhere:

Create Operations

Creating a Single Record

Basic create operation:

In a blog application I built, I needed to create users with their profile:

Creating Multiple Records

Bulk insert when seeding database:

Note: createMany doesn't return created records, only count.

Creating with Many-to-Many Relationships

Creating a post with tags:

Or create tags if they don't exist:

Read Operations

Finding a Single Record

Most common: finding by unique field:

Finding First Match

Find first record matching condition:

Finding Multiple Records

Filtering with Complex Conditions

Real-world example from a blog I built:

Selecting Specific Fields

Reduce data transfer by selecting only needed fields:

One of Prisma's best featuresβ€”eager loading relationships:

In a comments system I built, I needed posts with only approved comments:

Pagination

Two approaches I use:

Offset-based pagination:

Cursor-based pagination (better for large datasets):

Update Operations

Updating a Single Record

Updating with Increments

Useful for view counts, likes, etc.:

Updating or Creating (Upsert)

Extremely useful pattern I use constantly:

Updating Multiple Records

Delete Operations

Deleting a Single Record

Safe Delete (Check if Exists)

Deleting Multiple Records

Cascading Deletes

Remember our schema with onDelete: Cascade:

When we delete a user:

Transactions

When multiple operations must succeed or fail together.

Sequential Transactions

Batch Transactions

Real-World Transaction Example

From an e-commerce projectβ€”transferring points between users:

Error Handling

Common Prisma Errors

Handling Not Found

Performance Tips

Use Select to Limit Data

Batch Operations

Connection Pooling

What's Next?

We've covered the fundamentals of CRUD operations with Prisma. In Part 5, we'll explore advanced topics:

  • Complex filtering and aggregations

  • Raw SQL queries when needed

  • Full-text search

  • Database functions

  • Real-time features with Prisma Pulse

  • Deployment and production considerations

Conclusion

Prisma Client transforms database operations from error-prone string manipulation into type-safe, intuitive API calls. The type safety alone has saved me countless hours of debugging.

The operations we covered hereβ€”create, read, update, delete, and transactionsβ€”form the foundation of any database-backed application. I use these patterns daily in production systems handling thousands of requests.


This article is part of my personal knowledge sharing based on real projects I've built. All examples are adapted from actual code I've written and deployed to production.

Last updated