prisma
Skill0 starsChanged 3 months agoMITView on GitHub
Master Prisma ORM for type-safe database queries, schema design, migrations, and performance optimization in TypeScript applications
- Reads credentials
- Installs packages
7 other projects use a version of this.
Adopted by
Most recently taken up by
- nateslabach/skillstheir own version, first seen Nov 8, 2026
- G1Joshi/Agent-Skillstheir own version, first seen Oct 13, 2026
- juanquijandria/prisma-harnesstheir own version, first seen Oct 9, 2026
- Mindrally/skillstheir own version, first seen Oct 8, 2026
- trycompai/comptheir own version, first seen Oct 8, 2026
- elie222/inbox-zerotheir own version, first seen Oct 8, 2026
Used with
Projects with it also use react.
Other files people use alongside this one.
Files found in the same public projects as a version of this one, more often than they turn up anywhere else. Each project counts once, large collections count for less, and this file's own repository is left out.
VercelSkillreact
React renderer for json-render that turns JSON specs into React components. Use when working with @json-render/react, building React UIs from JSON, creating component catalogs, or rendering AI-generated specs.
Also in 3 projects that use this
Other versions7 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 7
- elie222/inbox-zero★ 13ksame name
- trycompai/comp★ 2.1ksame name
- Mindrally/skills★ 275same name
- G1Joshi/Agent-Skills★ 15same name
- YepAPI/skills★ 8same name
- nateslabach/skills★ 6same name
- juanquijandria/prisma-harness★ 2same name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository27 other files it gives its agents.
- architecture-designerSkill
- architecture-patternsSkill
- code-reviewSkill
- dockerSkill
- fastapiSkill
- feature-specificationSkill
- github-issue-resolverSkill
- github-opsSkill
- kubernetes-devopsSkill
- monitoringSkill
- nextjsSkill
- nginxSkill
- prd-to-ddd-designSkill
- prd-writerSkill
- react-expertSkill
- redisSkill
- redis-storeSkill
- requirements-analysisSkill
- shadcn-uiSkill
- ssh-essentialsSkill
- task-decomposerSkill
- task-development-workflowSkill
- trpc-best-practicesSkill
- typescript-proSkill
- typescriptSkill
- webhookSkill
- zodSkill
The file
We split this skill into the rules it gives an agent
11 rules. 0 are common, 8 are distinctive, and 3 are very specific to this project.
0
Common
Most of the 7 edited versions we read keep these.
8
Distinctive
This author's own choices. Worth a look.
3
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- could be automatic: a setting could enforce it
- Distinctive: line 26
Use this skill when:
- Distinctive: line 36
Don't use: when you need:
- Distinctive: line 79
Karpathy Principle: Simplicity First: - Start with SQLite for local development.
- Very specific: line 135
Karpathy Principle: Goal-Driven Execution: - After schema changes, run npx prisma generate immediately.
- Distinctive: line 307
Karpathy Principle: Surgical Changes: - Use transactions only when multiple operations must succeed or fail together.
- Very specific: line 356
Karpathy Principle: When NOT to Use: - Don't use Prisma for geospatial apps requiring complex polygon intersections or routing.
- Distinctive: line 675
Before deploying with Prisma:
- Distinctive: line 705
Use Prisma in API routes and Server Actions
- Distinctive: line 711
Use Prisma types for input/output validation
- Very specific: line 720
Run migrations in Dockerfile RUN step
- Distinctive: line 721
Use multi-stage builds for smaller images
“Common” is measured: kept by at least 6 in 10 of the 7 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Prisma - Next-Generation ORM for TypeScript
When to Use
Use this skill when:
- Building Node.js/TypeScript applications with relational databases
- Need type-safe database access with autocompletion
- Working with PostgreSQL, MySQL, SQLite, SQL Server, or MongoDB
- Managing database schema with version-controlled migrations
- Building REST or GraphQL APIs with complex data relationships
- Rapid prototyping with introspection from existing databases
- Serverless or edge deployments (with Prisma Accelerate)
Don't use when you need:
- Raw SQL performance for every query (use raw queries for hot paths)
- Non-relational databases (except MongoDB in preview)
- Multi-tenancy with dynamic schemas
- Extremely complex queries (100+ joins) - use raw SQL
- Maximum backwards compatibility (Prisma moves fast)
Karpathy Principle: Think Before Coding - Prisma schema design decisions are hard to change. Plan your relations, indexes, and constraints carefully. A @unique constraint today becomes a migration nightmare tomorrow.
Karpathy Principle: Trade-offs Everywhere - Prisma optimizes for developer experience (types, migrations, relations) at the cost of some raw SQL performance. For 95% of queries, this is the right trade-off. For hot paths, use $queryRaw.
Prerequisites
Required Knowledge
- TypeScript/JavaScript fundamentals
- SQL basics (SELECT, JOIN, WHERE, indexes)
- Async/await patterns
- Database concepts (primary keys, foreign keys, indexes)
Required Tools
# Install Prisma
npm install prisma --save-dev
npm install @prisma/client
# Initialize Prisma
npx prisma init
# This creates:
# - prisma/schema.prisma (your schema)
# - .env (database connection URL)Database Setup
# .env
DATABASE_URL="postgresql://user:password@localhost:5432/mydb"
# or
DATABASE_URL="mysql://user:password@localhost:3306/mydb"
# or
DATABASE_URL="file:./dev.db" # SQLiteKarpathy Principle: Simplicity First - Start with SQLite for local development. Migrate to PostgreSQL for production. Don't prematurely optimize to exotic databases.
Karpathy Principle: Own Your Migrations - Migrations are code. Review every generated migration before applying. Prisma generates good defaults, but YOU own the production safety (CONCURRENTLY, timeouts, backfills).
Core Workflows
1. Schema Design
Basic Model:
// 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?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
posts Post[]
}
model Post {
id String @id @default(cuid())
title String
content String?
published Boolean @default(false)
authorId String
author User @relation(fields: [authorId], references: [id], onDelete: Cascade)
tags Tag[]
@@index([authorId])
@@index([published])
}
model Tag {
id String @id @default(cuid())
name String @unique
posts Post[]
}Generate Client:
npx prisma generate # Creates @prisma/clientKarpathy Principle: Goal-Driven Execution - After schema changes, run npx prisma generate immediately. Don't wait for runtime errors. Type errors at compile time save debugging time.
2. CRUD Operations
Create:
import { PrismaClient } from '@prisma/client'
const prisma = new PrismaClient()
// Simple create
const user = await prisma.user.create({
data: {
email: 'john@example.com',
name: 'John Doe',
},
})
// Create with relations
const post = await prisma.post.create({
data: {
title: 'Hello World',
author: {
connect: { id: user.id }, // Connect existing user
},
tags: {
connectOrCreate: [
{
where: { name: 'TypeScript' },
create: { name: 'TypeScript' },
},
],
},
},
include: {
author: true,
tags: true,
},
})
// Batch create
await prisma.user.createMany({
data: [
{ email: 'alice@example.com', name: 'Alice' },
{ email: 'bob@example.com', name: 'Bob' },
],
skipDuplicates: true, // Ignore unique constraint violations
})Read:
// Find unique
const user = await prisma.user.findUnique({
where: { email: 'john@example.com' },
})
// Find first
const firstPublished = await prisma.post.findFirst({
where: { published: true },
orderBy: { createdAt: 'desc' },
})
// Find many with filtering
const posts = await prisma.post.findMany({
where: {
published: true,
author: {
email: { contains: '@example.com' },
},
},
include: {
author: {
select: { name: true, email: true },
},
tags: true,
},
orderBy: { createdAt: 'desc' },
take: 10,
skip: 0, // For pagination
})
// Count
const count = await prisma.post.count({
where: { published: true },
})
// Aggregate
const stats = await prisma.post.aggregate({
_count: true,
_max: { createdAt: true },
where: { published: true },
})Update:
// Update one
const updated = await prisma.user.update({
where: { id: user.id },
data: { name: 'Jane Doe' },
})
// Update many
await prisma.post.updateMany({
where: { published: false },
data: { published: true },
})
// Upsert (update or create)
const upserted = await prisma.user.upsert({
where: { email: 'john@example.com' },
update: { name: 'John Updated' },
create: {
email: 'john@example.com',
name: 'John New',
},
})Delete:
// Delete one
await prisma.post.delete({
where: { id: postId },
})
// Delete many
await prisma.post.deleteMany({
where: {
published: false,
createdAt: { lt: new Date('2023-01-01') },
},
})3. Transactions
Array Syntax (atomic operations):
const [deletedPosts, updatedUser] = await prisma.$transaction([
prisma.post.deleteMany({ where: { authorId: userId } }),
prisma.user.update({
where: { id: userId },
data: { name: 'Deleted User' },
}),
])Interactive Transactions (complex logic):
await prisma.$transaction(async (tx) => {
const user = await tx.user.findUnique({ where: { id: userId } })
if (!user) throw new Error('User not found')
await tx.post.create({
data: {
title: 'New Post',
authorId: user.id,
},
})
await tx.user.update({
where: { id: user.id },
data: { postCount: { increment: 1 } },
})
}, {
maxWait: 5000, // Max time to wait for transaction slot
timeout: 10000, // Max time transaction can run
})Karpathy Principle: Surgical Changes - Use transactions only when multiple operations must succeed or fail together. Single operations with relations are already transactional.
5. New Features (2024-2026)
createManyAndReturn (PostgreSQL, CockroachDB, SQLite):
// Before: createMany returns { count }
const result = await prisma.user.createMany({
data: [{ email: 'a@example.com' }, { email: 'b@example.com' }],
})
// result = { count: 2 }
// After: createManyAndReturn returns actual records
const users = await prisma.user.createManyAndReturn({
data: [{ email: 'a@example.com' }, { email: 'b@example.com' }],
})
// users = [{ id: 1, email: 'a@example.com' }, { id: 2, email: 'b@example.com' }]updateManyAndReturn (PostgreSQL, CockroachDB, SQLite):
const updated = await prisma.user.updateManyAndReturn({
where: { role: 'USER' },
data: { role: 'ADMIN' },
})
// Returns array of updated records, not just { count }Geometry/Spatial Queries (PostgreSQL + PostGIS):
model Location {
id String @id @default(cuid())
name String
position Unsupported("geometry(Point, 4326)")
}
// Find locations within 1km radius
const nearby = await prisma.location.findMany({
where: {
position: {
near: {
point: [13.4, 52.5], // [longitude, latitude]
maxDistance: 1000, // meters
},
},
},
})Karpathy Principle: When NOT to Use - Don't use Prisma for geospatial apps requiring complex polygon intersections or routing. Use PostGIS directly with $queryRaw for performance.
4. Relations and Includes
One-to-Many:
// Fetch user with all posts
const user = await prisma.user.findUnique({
where: { id: userId },
include: {
posts: {
where: { published: true },
orderBy: { createdAt: 'desc' },
take: 5,
},
},
})
// Count relations without loading them
const userWithCount = await prisma.user.findUnique({
where: { id: userId },
include: {
_count: {
select: { posts: true },
},
},
})Many-to-Many:
// Fetch post with tags
const post = await prisma.post.findUnique({
where: { id: postId },
include: { tags: true },
})
// Connect/disconnect many-to-many
await prisma.post.update({
where: { id: postId },
data: {
tags: {
connect: [{ id: tag1Id }, { id: tag2Id }],
disconnect: [{ id: tag3Id }],
},
},
})Common Patterns
1. Pagination (Cursor-Based)
async function getPosts(cursor?: string, take = 10) {
const posts = await prisma.post.findMany({
take: take + 1, // Fetch one extra to check if there's more
cursor: cursor ? { id: cursor } : undefined,
orderBy: { createdAt: 'desc' },
})
let nextCursor: string | undefined
if (posts.length > take) {
const nextItem = posts.pop()
nextCursor = nextItem!.id
}
return { posts, nextCursor }
}2. Soft Delete
model User {
id String @id @default(cuid())
email String @unique
deletedAt DateTime?
@@index([deletedAt])
}
// "Delete" user (soft delete)
await prisma.user.update({
where: { id: userId },
data: { deletedAt: new Date() },
})
// Query active users only
const activeUsers = await prisma.user.findMany({
where: { deletedAt: null },
})3. Full-Text Search
// PostgreSQL full-text search
const results = await prisma.$queryRaw`
SELECT * FROM "Post"
WHERE to_tsvector('english', title || ' ' || content)
@@ to_tsquery('english', ${query})
ORDER BY ts_rank(to_tsvector('english', title || ' ' || content), to_tsquery('english', ${query})) DESC
LIMIT 10
`4. Connection Pooling
// prisma/schema.prisma
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
// Prisma Accelerate for connection pooling
directUrl = env("DIRECT_DATABASE_URL")
}
// Or use connection URL parameters
// DATABASE_URL="postgresql://user:pass@host/db?connection_limit=10&pool_timeout=20"5. Type-Safe Reusable Queries
import { Prisma } from '@prisma/client'
const userWithPosts = Prisma.validator<Prisma.UserArgs>()({
include: {
posts: {
where: { published: true },
orderBy: { createdAt: 'desc' },
},
},
})
type UserWithPosts = Prisma.UserGetPayload<typeof userWithPosts>
async function getUser(id: string): Promise<UserWithPosts> {
return await prisma.user.findUniqueOrThrow({
where: { id },
...userWithPosts,
})
}6. Deeply Nested Writes
// Create user + posts + categories in one transaction
const user = await prisma.user.create({
data: {
email: 'emma@example.com',
posts: {
create: [
{
title: 'My first post',
categories: {
connectOrCreate: [
{ where: { name: 'Intro' }, create: { name: 'Intro' } },
{ where: { name: 'Social' }, create: { name: 'Social' } },
],
},
},
{
title: 'Second post',
categories: {
connect: [{ name: 'Social' }], // Reuse existing
},
},
],
},
},
include: {
posts: {
include: { categories: true },
},
},
})Common Pitfalls
1. N+1 Query Problem
Problem: Loading relations in a loop
❌ Bad:
const users = await prisma.user.findMany()
for (const user of users) {
const posts = await prisma.post.findMany({
where: { authorId: user.id }, // N queries!
})
}✅ Good:
const users = await prisma.user.findMany({
include: { posts: true }, // Single query with JOIN
})2. Missing Indexes
Problem: Slow queries on filtered/sorted fields
❌ Bad:
model Post {
authorId String
published Boolean
}✅ Good:
model Post {
authorId String
published Boolean
@@index([authorId])
@@index([published])
@@index([authorId, published]) // Compound for both filters
}3. Forgetting updatedAt
Problem: @updatedAt doesn't trigger on nested writes
❌ Bad:
await prisma.post.update({
where: { id: postId },
data: {
tags: { connect: [{ id: tagId }] },
},
})
// Post.updatedAt NOT updated!✅ Good:
await prisma.post.update({
where: { id: postId },
data: {
tags: { connect: [{ id: tagId }] },
updatedAt: new Date(), // Manual update
},
})4. Transaction Timeout
Problem: Long transactions hold connections
❌ Bad:
await prisma.$transaction(async (tx) => {
// Process 10,000 records one by one...
for (const item of items) {
await tx.item.create({ data: item }) // Very slow!
}
})✅ Good:
await prisma.item.createMany({
data: items, // Batch insert, much faster
})5. Raw Query Type Safety
Problem: $queryRaw returns unknown[]
❌ Bad:
const users = await prisma.$queryRaw`SELECT * FROM "User"`
// users is unknown[]✅ Good:
type UserRow = { id: string; email: string; name: string | null }
const users = await prisma.$queryRaw<UserRow[]>`SELECT * FROM "User"`
// users is UserRow[]6. Cascade Delete Configuration
Problem: Deleting parent fails because child records exist
❌ Bad:
model Post {
authorId String
author User @relation(fields: [authorId], references: [id])
}
// Deleting User with posts fails!✅ Good:
model Post {
authorId String
author User @relation(fields: [authorId], references: [id], onDelete: Cascade)
}
// Deleting User automatically deletes all postsOptions: Cascade, SetNull, Restrict, NoAction, SetDefault
Verification Checklist
Before deploying with Prisma:
Schema
- All foreign keys have
@relationfields - Indexes on all filtered/sorted fields
@updatedAton tables that need it- Cascade deletes configured correctly
- Enums used instead of strings (when applicable)
Queries
- No N+1 queries (use
includeorselect) - Pagination on large result sets (
take+cursor) - Transactions only where atomicity needed
- Raw queries typed with
Prisma.$queryRaw<Type>
Migrations
- All migrations tested in staging
- Backfilling data before constraints
- Indexes created concurrently (PostgreSQL)
- Rollback plan for each migration
Performance
- Connection pooling configured
- Query logging enabled in development
- Slow query monitoring in production
- Database indexes match query patterns
Integration with Other Skills
With Next.js
- Use Prisma in API routes and Server Actions
- Server Components can call Prisma directly
- Connection pooling essential for serverless
With tRPC
- Share Prisma client via tRPC context
- Use Prisma types for input/output validation
- Transactions in tRPC mutations
With TypeScript
- Full type inference for queries
- Zod schemas can mirror Prisma models
- Type-safe raw queries with generics
With Docker
- Run migrations in Dockerfile
RUNstep - Use multi-stage builds for smaller images
- Health checks with
prisma db execute
References
Official Docs
Guides
Community
Meta: Skill Quality
Completeness: ✅ Comprehensive (9/9 sections)
Karpathy Principles: ✅ 8 mentions
Code Examples: ✅ 28+ working examples
Production Tested: ✅ Used in NorthRelay, MemoryRelay
Last Updated: 2026-04-14
Coverage:
- ✅ Schema design and relations
- ✅ CRUD operations (all variants + new createManyAndReturn/updateManyAndReturn)
- ✅ Transactions (array + interactive)
- ✅ Pagination patterns
- ✅ Performance optimization
- ✅ Raw queries and type safety
- ✅ Migration strategies
- ✅ Connection pooling
- ✅ Cascade delete patterns
- ✅ Geospatial queries (PostGIS)
- ✅ Deeply nested writes
- ✅ Common pitfalls and solutions
Skill Level: Intermediate
Time to Learn: 4-6 hours
Prerequisites Met: TypeScript, SQL basics
Known Gaps: None - production-ready
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

