Help us improve
Share bugs, ideas, or general feedback.
From ensemble-development
Provides fast reference for Prisma 5+ ORM: schema design, migrations, type-safe CRUD, relations, transactions, error handling, testing, and integrations with Supabase, PlanetScale, Neon for TypeScript/JavaScript database access.
npx claudepluginhub fortiumpartners/ensemble --plugin ensemble-developmentHow this skill is triggered — by the user, by Claude, or both
Slash command
/ensemble-development:using-prismaThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
**Version**: 1.1.0 | **Target**: <500 lines | **Purpose**: Fast reference for Prisma operations
README.mdREFERENCE.mdVALIDATION.mdexamples/multi_database.example.tsexamples/nestjs_prisma.example.tsexamples/schema_patterns.example.prismaexamples/supabase_integration.example.tstemplates/README.mdtemplates/client.template.tstemplates/migration.template.tstemplates/model.template.prismatemplates/repository.template.tstemplates/rls_migration.template.sqltemplates/schema.template.prismatemplates/seed.template.tstemplates/supabase_schema.template.prismaTeaches SQL basics, database types (PostgreSQL, SQLite, MongoDB), ORMs like Prisma, schemas, migrations, and relationships for data modeling.
Provides expert guidance on Prisma ORM schema design, migrations, query optimization, relations modeling, and database operations for PostgreSQL, MySQL, SQLite.
Prisma ORM patterns for TypeScript backends — schema design, query optimization, transactions, pagination, and critical traps like updateMany returning count, $transaction timeouts, migrate dev resetting the DB, and serverless connection exhaustion.
Share bugs, ideas, or general feedback.
Version: 1.1.0 | Target: <500 lines | Purpose: Fast reference for Prisma operations
What is Prisma: Type-safe ORM with schema-first design for TypeScript/JavaScript. Auto-generates client from schema with full IntelliSense support.
When to Use This Skill:
Auto-Detection Triggers:
schema.prisma file present@prisma/client in dependenciesprisma in devDependenciesProgressive Disclosure:
my_project/
├── prisma/
│ ├── schema.prisma # Schema definition
│ ├── migrations/ # Migration history
│ └── seed.ts # Database seeding
├── src/
│ └── lib/prisma.ts # Client singleton
└── package.json
// PostgreSQL (local)
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
// Supabase (with pooling) - see Database Integrations
datasource db {
provider = "postgresql"
url = env("DATABASE_URL") // Pooled connection
directUrl = env("DIRECT_URL") // Direct for migrations
}
generator client {
provider = "prisma-client-js"
}
model User {
id String @id @default(cuid())
email String @unique
name String
bio String? // Optional
role Role @default(USER)
active Boolean @default(true)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
posts Post[] // Relation
@@index([email])
}
enum Role {
USER
ADMIN
}
| Type | Example | Notes |
|---|---|---|
String | name String | Text |
String? | bio String? | Optional text |
Int | count Int | Integer |
Float | price Float | Decimal |
Boolean | active Boolean | true/false |
DateTime | createdAt DateTime | Timestamp |
Json | metadata Json | JSON object |
String[] | tags String[] | PostgreSQL array |
More patterns: See REFERENCE.md - Schema Design Patterns for soft delete, audit fields, polymorphic relations, and multi-tenancy patterns.
npx prisma init # Initialize Prisma
npx prisma generate # Generate client after schema changes
npx prisma db push # Push schema (no migrations)
npx prisma migrate dev --name init # Create migration
npx prisma migrate reset # Reset database
npx prisma studio # Open GUI
npx prisma generate # Generate client (required in CI)
npx prisma migrate deploy # Apply pending migrations
npx prisma migrate status # Check migration status
npx prisma db pull # Pull schema from existing DB
npx prisma validate # Validate schema
npx prisma format # Format schema file
// src/lib/prisma.ts
import { PrismaClient } from "@prisma/client";
const globalForPrisma = globalThis as unknown as {
prisma: PrismaClient | undefined;
};
export const prisma = globalForPrisma.prisma ?? new PrismaClient();
if (process.env.NODE_ENV !== "production") {
globalForPrisma.prisma = prisma;
}
// Create
const user = await prisma.user.create({
data: { email: "user@example.com", name: "John" },
});
// Read
const user = await prisma.user.findUnique({
where: { id: "user_id" },
});
// Update
const updated = await prisma.user.update({
where: { id: "user_id" },
data: { name: "New Name" },
});
// Upsert
const upserted = await prisma.user.upsert({
where: { email: "user@example.com" },
update: { name: "Updated" },
create: { email: "user@example.com", name: "New" },
});
// Delete
const deleted = await prisma.user.delete({
where: { id: "user_id" },
});
const users = await prisma.user.findMany({
where: {
email: { contains: "@example.com" },
role: { in: ["ADMIN", "USER"] },
createdAt: { gte: new Date("2024-01-01") },
OR: [
{ name: { startsWith: "John" } },
{ name: { startsWith: "Jane" } },
],
},
});
// Offset pagination
const users = await prisma.user.findMany({
skip: (page - 1) * pageSize,
take: pageSize,
orderBy: { createdAt: "desc" },
});
// Cursor pagination (more efficient)
const users = await prisma.user.findMany({
take: 10,
cursor: { id: "last_seen_id" },
skip: 1,
});
// Select specific fields
const users = await prisma.user.findMany({
select: { id: true, name: true, email: true },
});
// Include relations
const users = await prisma.user.findMany({
include: { posts: { where: { published: true }, take: 5 } },
});
More patterns: See REFERENCE.md - Query Optimization for N+1 prevention, cursor pagination, and aggregation patterns.
model User {
id String @id @default(cuid())
posts Post[]
}
model Post {
id String @id @default(cuid())
author User @relation(fields: [authorId], references: [id])
authorId String
@@index([authorId])
}
model Post {
id String @id @default(cuid())
categories Category[]
}
model Category {
id String @id @default(cuid())
posts Post[]
}
// Create with relation
const user = await prisma.user.create({
data: {
email: "author@example.com",
posts: { create: { title: "First Post" } },
},
include: { posts: true },
});
// Filter by relation
const usersWithPosts = await prisma.user.findMany({
where: { posts: { some: { published: true } } },
});
More patterns: See REFERENCE.md - Advanced Relations for self-relations, polymorphic patterns, and explicit many-to-many.
const result = await prisma.$transaction(async (tx) => {
const order = await tx.order.create({ data: orderData });
await tx.inventory.update({
where: { id: productId },
data: { stock: { decrement: 1 } },
});
if ((await tx.inventory.findUnique({ where: { id: productId } }))!.stock < 0) {
throw new Error("Insufficient stock");
}
return order;
});
const [users, posts] = await prisma.$transaction([
prisma.user.findMany(),
prisma.post.findMany(),
]);
More patterns: See REFERENCE.md - Transactions & Concurrency for isolation levels, optimistic locking, and deadlock prevention.
datasource db {
provider = "postgresql"
url = env("DATABASE_URL") // Transaction pooler
directUrl = env("DIRECT_URL") // Direct for migrations
}
DATABASE_URL="postgres://postgres.[ref]:password@aws-0-region.pooler.supabase.com:6543/postgres?pgbouncer=true"
DIRECT_URL="postgres://postgres.[ref]:password@aws-0-region.supabase.com:5432/postgres"
datasource db {
provider = "mysql"
url = env("DATABASE_URL")
relationMode = "prisma" // Required: no foreign keys
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
directUrl = env("DIRECT_URL")
}
More patterns: See REFERENCE.md - Database Integrations for Supabase Auth integration, connection pooling, and edge runtime setup.
| Code | Description | Resolution |
|---|---|---|
| P2002 | Unique constraint failed | Duplicate value |
| P2003 | Foreign key constraint failed | Missing relation |
| P2025 | Record not found | Update/delete on missing record |
| P2024 | Connection pool timeout | Too many connections |
import { Prisma } from "@prisma/client";
try {
await prisma.user.create({ data });
} catch (error) {
if (error instanceof Prisma.PrismaClientKnownRequestError) {
if (error.code === "P2002") {
throw new ConflictError("Email already exists");
}
if (error.code === "P2025") {
throw new NotFoundError("Record not found");
}
}
throw error;
}
More patterns: See REFERENCE.md - Error Handling for comprehensive error mapping and retry strategies.
import { mockDeep, DeepMockProxy } from "jest-mock-extended";
import { PrismaClient } from "@prisma/client";
export const prismaMock = mockDeep<PrismaClient>();
jest.mock("./lib/prisma", () => ({
prisma: prismaMock,
}));
// In tests
prismaMock.user.create.mockResolvedValue(mockUser);
beforeEach(async () => {
await prisma.$executeRaw`TRUNCATE TABLE "User" CASCADE`;
});
afterAll(async () => {
await prisma.$disconnect();
});
More patterns: See REFERENCE.md - Testing Strategies for integration testing, test containers, and CI/CD setup.
# Development
npx prisma generate # Regenerate client
npx prisma db push # Push schema changes
npx prisma migrate dev # Create migration
npx prisma studio # GUI browser
# Production
npx prisma generate # Required in CI
npx prisma migrate deploy # Apply migrations
// CRUD
prisma.model.create({ data })
prisma.model.findUnique({ where })
prisma.model.findMany({ where, orderBy, take, skip })
prisma.model.update({ where, data })
prisma.model.delete({ where })
prisma.model.upsert({ where, create, update })
// Relations
include: { relation: true }
include: { relation: { where, take } }
where: { relation: { some: {} } }
// Transactions
prisma.$transaction(async (tx) => { ... })
prisma.$transaction([query1, query2])
Progressive Disclosure: Start here for quick reference. Load REFERENCE.md for comprehensive patterns, advanced configurations, and production deployment.
Skill Version: 1.1.0