Skip to main content
rule

prisma — Cursor rule: what it does, how to install

A Cursor rule that keeps your agent honest about Prisma ORM: one client instance, narrow queries, sane migrations.

Install into Cursor · Manually: put the files in place All methods and platforms ↓
.cursor/rules/prisma.mdc
Open on GitHub

What prisma does

Drop .cursor/rules/prisma.mdc into your project and Cursor applies it whenever it touches **/*.prisma. The file spells out how schemas should look: config in prisma.config.ts, a single PrismaClient, PascalCase models, camelCase fields, plus createdAt, updatedAt and deletedAt for auditing and soft deletes.

A second section covers query cost. The agent is told to pull only the columns it needs with select and include, to reach for createMany() and updateMany() on large sets, and to avoid the N+1 trap. Migrations get descriptive names — npx prisma migrate dev --name add-user-profile-fields — and applied migrations are off limits for edits, since rewriting them drifts your schema between environments.

The examples assume TypeScript and Prisma ORM v7+, which is why the config snippet uses defineConfig. The source also starts describing the official Prisma VS Code extension before it cuts off. On an older Prisma major or a non-TypeScript setup, expect to adapt the snippets yourself.

What it helps with

  • stop instantiating new PrismaClient() on every request
  • cut queries that fetch every field and relation
  • replace per-row inserts in a loop with createMany()
  • give migrations readable names instead of init
  • add audit and soft-delete fields to models

Example prompts for the agent

  • apply the prisma rule and refactor lib/prisma.ts to a single client instance
  • rewrite this query to select only id and email
  • check prisma/schema.prisma against the prisma rule

How to install prisma

Manually: put the files in place

.cursor/rules/prisma.mdc

Frontmatter: description, globs, alwaysApply

Step by step, with commands for each platform: Cursor rules: .mdc files, four modes and what replaced .cursorrules

Questions about prisma

How do I install prisma in Cursor?

Place the rule file at .cursor/rules/prisma.mdc in your project root. Cursor picks it up and applies it to files matching **/*.prisma.

What does the prisma rule do?

It tells the agent how to work with Prisma ORM: one client instance, targeted selects, bulk writes, descriptive migration names. That keeps queries and schema predictable.

Which Prisma version does it target?

The config examples assume Prisma ORM v7+ with TypeScript. On older majors the prisma.config.ts approach won't apply.

Source text

prisma.mdc · CC0-1.0
---
description: Enforce best practices for Prisma ORM, ensuring type-safe, performant, and maintainable database interactions in modern TypeScript applications.
globs: **/*.prisma
---
# prisma Best Practices

Prisma is the definitive Type-first ORM for modern TypeScript applications. Adhere to these guidelines for optimal performance, maintainability, and type safety, leveraging the latest TypeScript/WASM engine for a superior developer experience.

## 1. Code Organization & Client Management

Always use `prisma.config.ts` for configuration and ensure a single, globally accessible `PrismaClient` instance.

### ✅ GOOD: Type-Safe Configuration (`prisma.config.ts`)

Configure Prisma CLI with full type safety using `defineConfig` or `satisfies PrismaConfig`. This is the standard for Prisma ORM v7+.

```typescript
// prisma.config.ts
import 'dotenv/config';
import { defineConfig, env } from 'prisma/config'; // v7+ config import

export default defineConfig({
  schema: 'prisma/schema.prisma',
  migrations: {
    path: 'prisma/migrations',
    seed: 'tsx prisma/seed.ts', // Use tsx for TypeScript seed scripts
  },
  datasource: {
    url: env('DATABASE_URL'), // Always use environment variables for sensitive data
  },
});
```

### ✅ GOOD: Singleton PrismaClient Instance

Prevent connection pool exhaustion and memory leaks, especially in hot-reloading development environments like Next.js.

```typescript
// lib/prisma.ts
import { PrismaClient } from '@prisma/client'; // Import generated client

const globalForPrisma = global as unknown as { prisma: PrismaClient };

export const prisma =
  globalForPrisma.prisma ||
  new PrismaClient({
    log: ['query', 'info', 'warn', 'error'], // Essential for observability and debugging
  });

if (process.env.NODE_ENV !== 'production') {
  globalForPrisma.prisma = prisma; // Persist client across hot reloads in dev
}
```

❌ **BAD**: Instantiating `new PrismaClient()` in every request or module.

```typescript
// ❌ BAD: Creates multiple PrismaClient instances
async function getPosts() {
  const prisma = new PrismaClient(); // This will exhaust your connection pool
  await prisma.post.findMany();
}
```

## 2. Data Modeling & Schema Design

Design your `schema.prisma` for clarity, consistency, and database efficiency.

### ✅ GOOD: Naming Conventions & Essential Fields

Use singular, PascalCase for models and camelCase for fields. Leverage enums for fixed domains. Include `createdAt`, `updatedAt`, and `deletedAt` for robust auditing and soft deletes.

```prisma
// prisma/schema.prisma
model User {
  id        String   @id @default(uuid()) // Prefer UUIDs for distributed systems
  email     String   @unique
  name      String?
  role      Role     @default(USER)     // Use enums for constrained values
  posts     Post[]
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
  deletedAt DateTime? // Crucial for soft deletes and data integrity
}

model Post {
  id        Int      @id @default(autoincrement())
  title     String
  content   String?
  published Boolean  @default(false)
  author    User     @relation(fields: [authorId], references: [id])
  authorId  String
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
}

enum Role {
  USER
  ADMIN
  EDITOR
}
```

### ✅ GOOD: Composite Keys & Indexes

Define composite unique constraints and indexes for efficient lookups on multiple fields.

```prisma
model OrderItem {
  orderId   String
  productId String
  quantity  Int

  @@id([orderId, productId]) // Composite primary key
  @@index([productId])       // Index for efficient lookups by product
}
```

## 3. Query Optimization & Performance

Avoid over-fetching, use bulk operations, and leverage Prisma's built-in optimizations.

### ✅ GOOD: Selective Data Fetching (`select`/`include`)

Only fetch the data you explicitly need. This drastically reduces network overhead and memory usage.

```typescript
// ✅ GOOD: Fetch only ID and email
const users = await prisma.user.findMany({
  select: {
    id: true,
    email: true,
  },
});

// ✅ GOOD: Include related posts only when necessary
const userWithPosts = await prisma.user.findUnique({
  where: { id: 'some-uuid' },
  include: {
    posts: {
      select: {
        id: true,
        title: true,
      },
    },
  },
});
```

❌ **BAD**: Over-fetching all fields and relations.

```typescript
// ❌ BAD: Fetches ALL user fields and ALL post fields, even if not used
const users = await prisma.user.findMany({
  include: { posts: true },
});
```

### ✅ GOOD: Bulk Operations

For large data sets, prefer `createMany()`/`createManyAndReturn()` and `updateMany()` over individual operations. Batch thousands of records for optimal performance.

```typescript
// ✅ GOOD: Bulk create multiple users
const newUsers = await prisma.user.createMany({
  data: [
    { email: '[email protected]', name: 'Alice' },
    { email: '[email protected]', name: 'Bob' },
  ],
  skipDuplicates: true, // Prevents errors on existing records
});

// ✅ GOOD: Batch writes for very large datasets (e.g., 1000 records per batch)
async function bulkInsert(data: UserCreateInput[]) {
  const batchSize = 1000;
  for (let i = 0; i < data.length; i += batchSize) {
    const batch = data.slice(i, i + batchSize);
    await prisma.user.createMany({ data: batch });
  }
}
```

❌ **BAD**: Individual inserts in a loop for many records.

```typescript
// ❌ BAD: N separate database queries for N records
for (const user of manyUsers) {
  await prisma.user.create({ data: user });
}
```

### ✅ GOOD: Solve N+1 with `include` or Fluent API

Leverage Prisma's dataloader for `findUnique` (which batches queries) or use `include` for related data to avoid the N+1 problem.

```typescript
// ✅ GOOD: Using include to fetch related data in a single query
const usersWithPosts = await prisma.user.findMany({
  include: {
    posts: true,
  },
});

// ✅ GOOD: Fluent API for specific related data (batches findUnique calls)
const userPosts = await prisma.user.findUnique({
  where: { id: 'some-uuid' },
})?.posts({
  where: { published: true },
});
```

## 4. Migration Patterns

Maintain a clean, consistent, and reliable migration history.

### ✅ GOOD: Descriptive Migration Names

Use `npx prisma migrate dev --name <descriptive-name>` for clear, self-documenting migration history.

```bash
npx prisma migrate dev --name add-user-profile-fields
```

❌ **BAD**: Generic names like `init` or `migration` provide no context.

### ✅ GOOD: Never Edit Applied Migrations

Once a migration is applied to *any* environment (dev, staging, production), *never* modify its SQL. This prevents schema drift, data corruption, and deployment issues. If changes are needed, create a new migration.

## 5. Editor Tooling

Maximize productivity and maintain code quality with the official Prisma VS Code extension and Prettier.

### ✅ GOOD: Prisma VS Code Extension & Prettier

Install the official [Prisma VS Code extension](https://marketplace.visualstudio.com/items?itemName=Prisma.prisma) and `prettier-plugin-prisma`. Configure your `settings.json` for automatic formatting on save.

```json
// .vscode/settings.json
{
  "editor.formatOnSave": true,
  "[prisma]": {
    "editor.defaultFormatter": "Prisma.prisma"
  }
}
```

This ensures consistent schema formatting, linting, and provides features like go-to-definition and quick-fixes.

© sanjeed5 · CC0-1.0 · sanjeed5/awesome-cursor-rules-mdc

Similar IDE rules

All IDE rules for Data and databases →

From the same set69

Project sponsors

Companies that keep this analytics open
Gold sponsor

Impressions, clicks and code copies — open statistics. We keep the numbers public for the same reason NeBlask itself is public. Become a sponsor