home / skills / openclaw / skills / prisma
This skill helps you design efficient Prisma queries and schemas in Python, guiding you to avoid common pitfalls and optimize performance.
npx playbooks add skill openclaw/skills --skill prismaReview the files below or copy the command above to add this skill to your agents.
---
name: Prisma
description: Write efficient Prisma queries, design schemas, and avoid common ORM pitfalls.
metadata:
category: database
skills: ["prisma", "orm", "database", "typescript", "nodejs"]
---
## Schema Design Traps
- `@default(cuid())` over `@default(uuid())` for IDs—shorter, URL-safe, still unique
- `@updatedAt` doesn't update on nested writes—must touch parent record explicitly
- Implicit many-to-many creates join table you can't customize—use explicit for extra fields
- `@unique` on nullable field allows multiple NULLs—intended behavior but often surprising
- Enum changes require migration—can't add values without downtime unless using String
## Query Patterns I Forget
- `findUniqueOrThrow` / `findFirstOrThrow`—cleaner than null check after findUnique
- `createMany` skips hooks and returns count only—use `create` in loop if you need records back
- `upsert` requires unique field in where—can't upsert on non-unique compound conditions
- `connectOrCreate` in nested writes—avoids separate existence check
- `select` and `include` are mutually exclusive—can't mix; use nested select inside include
## N+1 Query Prevention
- Default queries don't include relations—every access triggers new query
- `include` everything you'll access—check logs for unexpected queries
- Middleware can't see includes—adding includes in middleware doesn't help
- `findMany` + `include` better than loop of `findUnique`—single query vs N queries
- Dataloader pattern for GraphQL resolvers—Prisma doesn't batch automatically
## Transaction Gotchas
- `$transaction([])` array syntax rolls back all on any failure—use for atomic operations
- Interactive transactions `$transaction(async (tx) => {})` hold connection—keep short
- Default 5s timeout on interactive transactions—increase for long operations
- Nested writes are already transactional—don't wrap single create with relations in transaction
- `$transaction` doesn't retry on conflict—implement retry logic for optimistic locking
## Type Safety Gaps
- `include` result type doesn't narrow—TypeScript thinks relations might be undefined
- Raw queries return `unknown[]`—need manual type assertion or Prisma.$queryRaw<Type>
- JSON fields are `JsonValue`—cast needed; consider using typed JSON libraries
- `Prisma.validator` for reusable query fragments with correct types
- Return types of `$executeRaw` is count—not the affected rows
## Migration Issues
- `prisma db push` for prototyping—`prisma migrate dev` for version control
- `db push` can drop data silently—never use in production
- Shadow database required for `migrate dev`—needs create permission or separate DB
- Renaming field = drop + create by default—use `@map` to keep data
- Large table migrations lock table—consider running raw SQL with concurrent indexes
## Performance Traps
- `findMany` without `take` can return millions—always paginate
- `count()` scans table—expensive on large tables; consider approximate or cached counts
- `include` with large relations loads everything—use cursor pagination for big lists
- Relation counts: `_count: { select: { posts: true } }`—single query, not N+1
- `orderBy` on non-indexed field = slow—ensure indexes match sort patterns
## Raw Query Patterns
- `$queryRaw` for reads, `$executeRaw` for writes—different return types
- Use `Prisma.sql` template for safe interpolation—never string concatenation
- Raw queries bypass Prisma hooks and middleware—intentional but easy to forget
- `$queryRawUnsafe` exists but name is a warning—use only for dynamic column names
- Raw results use database column names—not Prisma field names if `@map` used
## Connection Management
- Default pool size 5—too low for production; set `connection_limit` in URL
- PlanetScale/serverless needs `?pool_timeout=0`—prevents connection exhaustion
- `$disconnect()` in scripts and tests—lambda/serverless should manage differently
- Prisma Accelerate or Data Proxy for edge/serverless—direct DB connections don't scale
## Middleware Patterns
- Soft delete via middleware: intercept `delete`, convert to `update`—but `deleteMany` needs handling
- Audit logging: `$use` captures all queries—but adds latency to every operation
- Middleware runs in order added—earlier middleware sees raw params
- Can't modify `include` in middleware—transform happens before middleware
## Common Mistakes
- Forgetting `await`—Prisma returns promises; queries don't execute without await
- `update` without where = error—unlike some ORMs, Prisma requires explicit where
- Decimal fields return strings—Prisma Decimal type, not JavaScript number
- `@relation` names must match—cryptic error if they don't
- Schema drift: production differs from migrations—run `prisma migrate deploy` in CI
This skill helps you write efficient Prisma queries, design resilient schemas, and avoid common ORM pitfalls. It focuses on practical patterns for schema design, query performance, transactions, type safety, migrations, and connection management. Use it to reduce runtime errors, prevent N+1 problems, and keep migrations safe in production.
The skill inspects common Prisma patterns and suggests concrete fixes: schema defaults and enums, relation handling, include vs select usage, and transaction safety. It highlights query-level optimizations like batching, proper includes, and raw query safety, and it flags migration and connection configuration risks. Recommendations are short, actionable, and tied to real-world failure modes.
When should I use createMany versus create?
Use createMany for bulk inserts when you only need a count back and want speed. Use create (or a loop of create) when you need returned records, hooks, or nested writes.
How do I avoid implicit many-to-many limitations?
Define an explicit join model so you can add fields, constraints, and custom indexes instead of relying on the auto-generated join table.