From harness-claude
Optimizes Prisma queries using select, findUnique batching, N+1 prevention, bulk operations, indexing, query logging, connection pooling, and cursor pagination.
How this skill is triggered — by the user, by Claude, or both
Slash command
/harness-claude:prisma-performance-patternsThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
> Optimize Prisma queries with select, findUnique index hits, batching, and avoiding N+1
Optimize Prisma queries with select, findUnique index hits, batching, and avoiding N+1
select reduces data transfer and avoids loading large text/JSON columns:const users = await prisma.user.findMany({
select: { id: true, name: true, email: true },
// NOT: include the entire User with all 20 fields
});
findUnique over findFirst when querying by @id or @unique fields. Prisma batches findUnique calls automatically via internal DataLoader:// These two calls in the same tick are batched into one SQL query
const [user1, user2] = await Promise.all([
prisma.user.findUnique({ where: { id: id1 } }),
prisma.user.findUnique({ where: { id: id2 } }),
]);
include — instead of querying related records in a loop:// BAD: N+1 — one query per user
const users = await prisma.user.findMany();
for (const user of users) {
user.posts = await prisma.post.findMany({ where: { authorId: user.id } });
}
// GOOD: single include
const users = await prisma.user.findMany({
include: { posts: true },
});
include level adds a database query. For deep nesting, use raw SQL with JOINs instead:// Avoid: 4 levels of include = 4 queries
const data = await prisma.user.findMany({
include: { posts: { include: { comments: { include: { author: true } } } } },
});
// Better: raw query with JOINs for the specific data shape you need
createMany for bulk inserts — one INSERT instead of N:await prisma.post.createMany({
data: posts,
skipDuplicates: true,
});
await prisma.$transaction(
items.map((item) =>
prisma.inventory.update({
where: { sku: item.sku },
data: { quantity: { decrement: item.qty } },
})
)
);
model Post {
authorId String
createdAt DateTime @default(now())
published Boolean
@@index([authorId, createdAt])
@@index([published, createdAt])
}
const prisma = new PrismaClient({
log: [{ emit: 'event', level: 'query' }],
});
prisma.$on('query', (e) => {
if (e.duration > 100) console.warn(`Slow query (${e.duration}ms):`, e.query);
});
DATABASE_URL="postgresql://user:pass@host:5432/db?connection_limit=10&pool_timeout=30"
skip values:const page = await prisma.post.findMany({
cursor: { id: lastId },
skip: 1,
take: 20,
orderBy: { id: 'asc' },
});
Prisma generates SQL queries for every Client operation. Understanding the generated SQL helps diagnose performance issues.
DataLoader batching: Prisma's internal DataLoader batches findUnique calls that occur in the same event loop tick into a single WHERE id IN (...) query. This only works with findUnique — findFirst and findMany are never batched.
include query mechanics: Each include generates a separate SELECT with a WHERE foreign_key IN (...) clause using the parent IDs. This is more efficient than N+1 but still adds one query per include level. For read-heavy endpoints with complex data shapes, consider denormalizing or using raw SQL views.
Connection pool sizing: The default pool size is num_physical_cpus * 2 + 1. For serverless environments (Vercel, AWS Lambda), set connection_limit=1 and use an external pooler (PgBouncer, Prisma Data Proxy) to avoid exhausting database connections.
Prisma Accelerate / Data Proxy: For edge deployments and serverless, Prisma Accelerate provides connection pooling and global caching. It adds latency per query but solves the connection exhaustion problem.
Common performance antipatterns:
take or cursorinclude with findMany on large collections — fetches all related records for all resultscount alongside findMany — two separate queries. Use a raw query with COUNT(*) OVER() for total count in one passhttps://prisma.io/docs/orm/prisma-client/queries/query-optimization-performance
npx claudepluginhub intense-visions/harness-engineering --plugin harness-claudeProduction patterns and non-obvious traps for Prisma ORM in TypeScript backends — schema design, query optimization, transactions, pagination, bulk operations, migrations, and serverless deployment gotchas.
Provides expert guidance on Prisma ORM schema design, migrations, query optimization, relations modeling, and database operations for PostgreSQL, MySQL, SQLite.
Provides Prisma Client query patterns: findUnique/findMany, create/update/delete, upsert, select, include, nested writes, and client instantiation best practices.