Cursor rules for Prisma database development with TypeScript, migrations, and query optimization.
.cursorrules in your project rootYou are an expert in Prisma ORM and database design.
## Schema Design
```prisma
// schema.prisma
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
model User {
id String @id @default(cuid())
email String @unique
name String?
password String
role Role @default(USER)
posts Post[]
profile Profile?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([email])
@@map("users")
}
model Post {
id String @id @default(cuid())
title String
content String?
published Boolean @default(false)
author User @relation(fields: [authorId], references: [id], onDelete: Cascade)
authorId String
tags Tag[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([authorId])
@@index([published])
@@map("posts")
}
model Tag {
id String @id @default(cuid())
name String @unique
posts Post[]
@@map("tags")
}
enum Role {
USER
ADMIN
}
```
## Query Patterns
```typescript
// ✅ Use select for partial data
const users = await prisma.user.findMany({
select: {
id: true,
email: true,
name: true,
},
});
// ✅ Use include for relations
const userWithPosts = await prisma.user.findUnique({
where: { id },
include: {
posts: {
where: { published: true },
orderBy: { createdAt: 'desc' },
take: 10,
},
},
});
// ✅ Use transactions for multiple operations
const [user, post] = await prisma.$transaction([
prisma.user.create({ data: userData }),
prisma.post.create({ data: postData }),
]);
// ✅ Interactive transactions
const result = await prisma.$transaction(async (tx) => {
const user = await tx.user.findUnique({ where: { id } });
if (!user) throw new Error('User not found');
return tx.post.create({
data: { ...postData, authorId: user.id },
});
});
```
## Pagination
```typescript
interface PaginationParams {
page: number;
limit: number;
}
async function getPaginatedPosts({ page, limit }: PaginationParams) {
const [posts, total] = await prisma.$transaction([
prisma.post.findMany({
skip: (page - 1) * limit,
take: limit,
orderBy: { createdAt: 'desc' },
}),
prisma.post.count(),
]);
return {
data: posts,
pagination: {
page,
limit,
total,
totalPages: Math.ceil(total / limit),
},
};
}
// Cursor-based pagination (better for large datasets)
async function getPostsCursor(cursor?: string, limit = 10) {
const posts = await prisma.post.findMany({
take: limit + 1,
...(cursor && {
cursor: { id: cursor },
skip: 1,
}),
orderBy: { createdAt: 'desc' },
});
const hasMore = posts.length > limit;
const data = hasMore ? posts.slice(0, -1) : posts;
return {
data,
nextCursor: hasMore ? data[data.length - 1].id : null,
};
}
```
## Soft Delete Pattern
```typescript
// Middleware for soft delete
prisma.$use(async (params, next) => {
if (params.model === 'Post') {
if (params.action === 'delete') {
params.action = 'update';
params.args['data'] = { deletedAt: new Date() };
}
if (params.action === 'deleteMany') {
params.action = 'updateMany';
params.args['data'] = { deletedAt: new Date() };
}
}
return next(params);
});
// Filter soft deleted records
const activePosts = await prisma.post.findMany({
where: { deletedAt: null },
});
```Comprehensive Cursor rules for Next.js 14+ with App Router, including routing, layouts, and API patterns.
Cursor rules for TypeScript with strict type checking, advanced patterns, and best practices.
Cursor rules for Tailwind CSS development with responsive design, custom components, and dark mode.
Cursor
database
AI coding rules customize how Cursor generates and refactors code for your project. Follow these steps to install Prisma ORM Best Practices.
.cursor/rules, for Windsurf use .windsurfrulesComprehensive Cursor rules for Next.js 14+ with App Router, including routing, layouts, and API patterns.
Cursor rules for TypeScript with strict type checking, advanced patterns, and best practices.
Cursor rules for Tailwind CSS development with responsive design, custom components, and dark mode.