api-database-prisma-7a8b15 — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited api-database-prisma-7a8b15 (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Quick Guide: Use Prisma ORM for type-safe database queries with auto-generated TypeScript types. Schema-first design with declarative migrations. Useincludefor relations,$transactionfor atomic operations. Singleton pattern required in development to avoid connection exhaustion. Always usetx(notprisma) inside interactive transaction callbacks.
<critical_requirements>
All code must follow project conventions in CLAUDE.md (kebab-case, named exports, import ordering, import type, named constants)(You MUST use the singleton pattern for PrismaClient in development to prevent connection exhaustion from hot reloading)
(You MUST use `tx` parameter (NOT `prisma`) inside interactive transaction callbacks to ensure atomicity)
(You MUST use `include` or nested `select` for relational queries - avoid N+1 by fetching relations in the same query)
(You MUST define `@relation` with explicit `fields` and `references` for all foreign key relationships)
</critical_requirements>
Auto-detection: prisma, @prisma/client, PrismaClient, prisma.schema, prisma migrate, findUnique, findMany, include, $transaction
When to use:
When NOT to use:
Key patterns covered:
include and nested selectDetailed Resources:
<philosophy>
Prisma ORM provides a declarative schema language that generates type-safe database clients. The schema serves as the single source of truth for your data model, TypeScript types, and migrations.
Core principles:
schema.prisma, generate everything elseprisma.user.findMany())</philosophy>
<patterns>
Use singleton pattern to prevent connection pool exhaustion during development hot reloading. Without this, each hot reload creates a new PrismaClient with its own connection pool, quickly exhausting database connections.
// lib/db/client.ts
import { PrismaClient } from "@prisma/client";
const globalForPrisma = globalThis as unknown as {
prisma: PrismaClient | undefined;
};
const createPrismaClient = () => {
return new PrismaClient({
log:
process.env.NODE_ENV === "development"
? ["query", "error", "warn"]
: ["error"],
});
};
export const prisma = globalForPrisma.prisma ?? createPrismaClient();
if (process.env.NODE_ENV !== "production") {
globalForPrisma.prisma = prisma;
}Why good: globalThis persists across hot reloads, conditional logging avoids production noise
See examples/core.md for serverless connection patterns.
Define models with relations, constraints, and defaults. The schema is the source of truth.
model User {
id String @id @default(cuid())
email String @unique
name String?
role Role @default(USER)
posts Post[]
profile Profile?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@map("users")
}
model Post {
id String @id @default(cuid())
title String
content String?
published Boolean @default(false)
author User @relation(fields: [authorId], references: [id], onDelete: Cascade)
authorId String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([authorId])
@@map("posts")
}Why good: cuid() for collision-resistant IDs, @updatedAt auto-tracks changes, @relation with onDelete: Cascade prevents orphans, @@index on foreign keys, @@map for snake_case DB tables with PascalCase in code
All queries are fully typed based on your schema. Key operations:
const DEFAULT_PAGE_SIZE = 20;
const MAX_PAGE_SIZE = 100;
// Find by unique field - returns T | null
const user = await prisma.user.findUnique({
where: { email: "[email protected]" },
});
// Find many with filters + pagination
const users = await prisma.user.findMany({
where: {
role: { in: ["USER", "MODERATOR"] },
createdAt: { gte: new Date("2024-01-01") },
},
orderBy: { name: "asc" },
take: DEFAULT_PAGE_SIZE,
});
// Upsert - atomic create-or-update
const upserted = await prisma.user.upsert({
where: { email: "[email protected]" },
create: { email: "[email protected]", name: "Alice" },
update: { name: "Alice Updated" },
});Why good: Type-safe operations catch errors at compile time, findUnique returns T | null forcing null handling, upsert is atomic
See examples/core.md for complete CRUD operations, filtering, and pagination patterns.
Fetch related data efficiently using include or nested select to avoid N+1 queries.
// Include related records - single query
const userWithPosts = await prisma.user.findUnique({
where: { id: userId },
include: {
posts: {
where: { published: true },
orderBy: { createdAt: "desc" },
take: 10,
},
profile: true,
},
});
// Select specific fields only - smaller payload
const userSummary = await prisma.user.findUnique({
where: { id: userId },
select: {
id: true,
name: true,
posts: { select: { id: true, title: true } },
},
});Why good: Single query avoids N+1, include fetches all fields, select reduces payload. Never loop queries per record — use include or select instead.
See examples/relations.md for relation filters, many-to-many, self-relations, include vs select, and N+1 anti-patterns.
Ensure atomic operations across multiple writes. Three types available:
// Nested writes - implicit transaction (cleanest for related records)
const user = await prisma.user.create({
data: {
email: "[email protected]",
name: "Alice",
profile: { create: { bio: "Developer" } },
posts: { create: [{ title: "First Post", published: true }] },
},
include: { profile: true, posts: true },
});
// Interactive transaction - ALWAYS use tx, never prisma
return await prisma.$transaction(async (tx) => {
const sender = await tx.account.update({
where: { id: fromId },
data: { balance: { decrement: amount } },
});
if (sender.balance < MINIMUM_BALANCE) throw new Error("Insufficient funds");
return await tx.account.update({
where: { id: toId },
data: { balance: { increment: amount } },
});
});Why good: Nested writes for related records, interactive transactions enable business logic with automatic rollback. Using prisma instead of tx inside the callback bypasses transaction context.
See examples/transactions.md for batch transactions, error handling, optimistic concurrency, and transaction options.
Handle $disconnect() on beforeExit to prevent connection leaks. For serverless environments, use a connection pooler (PgBouncer, Prisma Accelerate) via a separate DATABASE_URL_WITH_POOLER environment variable.
See examples/core.md for graceful shutdown and serverless connection patterns.
</patterns>
<red_flags>
High Priority Issues:
prisma instead of tx in interactive transactions - bypasses transaction contextinclude or select instead@relation attributes - ambiguous foreign keys cause migration errorsMedium Priority Issues:
onDelete cascade - orphaned records when parent deletedinclude when only some needed - use selectGotchas & Edge Cases:
createMany doesn't return created records (use createManyAndReturn on PostgreSQL/CockroachDB/SQLite)updateMany and deleteMany don't automatically update @updatedAt fieldsJson fields are typed as JsonValue - need runtime validation at parse boundaryDecimal fields return Prisma.Decimal type - convert with .toNumber()timeout optionfindFirst without orderBy returns non-deterministic results</red_flags>
<critical_reminders>
All code must follow project conventions in CLAUDE.md
(You MUST use the singleton pattern for PrismaClient in development to prevent connection exhaustion from hot reloading)
(You MUST use `tx` parameter (NOT `prisma`) inside interactive transaction callbacks to ensure atomicity)
(You MUST use `include` or nested `select` for relational queries - avoid N+1 by fetching relations in the same query)
(You MUST define `@relation` with explicit `fields` and `references` for all foreign key relationships)
Failure to follow these rules will exhaust database connections, break transaction atomicity, cause N+1 performance problems, and create unclear relation definitions.
</critical_reminders>
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.