Manage PrismaClient lifecycle with graceful shutdown, proper disconnect timing, and logging configuration. Use when setting up application shutdown handlers, configuring logging for development or production, or implementing proper connection cleanup in Node.js servers, serverless functions, or test suites.
Teaches proper PrismaClient lifecycle patterns for connection cleanup and logging following Prisma 6 best practices.
/plugin marketplace add djankies/claude-configs/plugin install prisma-6@claude-configsThis skill is limited to using the following tools:
Teaches proper PrismaClient lifecycle patterns for connection cleanup and logging following Prisma 6 best practices.
Activates when: Setting up shutdown handlers (SIGINT, SIGTERM), configuring PrismaClient logging, implementing connection cleanup in servers/serverless/tests, writing test teardown logic, or user mentions "shutdown", "disconnect", "cleanup", "logging", "graceful exit".
Why it matters: Proper lifecycle management ensures clean connection closure on shutdown, prevents hanging connections from exhausting database resources, provides development/production visibility through logging, and prevents connection leaks in tests.
import express from 'express'
import { prisma } from './lib/prisma'
const app = express()
const server = app.listen(3000)
async function gracefulShutdown(signal: string) {
console.log(`Received ${signal}, closing gracefully...`)
server.close(async () => {
await prisma.$disconnect()
process.exit(0)
})
setTimeout(() => { process.exit(1) }, 10000) // Force exit if hung
}
process.on('SIGINT', () => gracefulShutdown('SIGINT'))
process.on('
SIGTERM', () => gracefulShutdown('SIGTERM'))
Close HTTP server first (stops new requests), then $disconnect() database, add 10s timeout to force exit if cleanup hangs. Fastify simplifies this with fastify.addHook('onClose', () => prisma.$disconnect()).
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient();
afterAll(async () => {
await prisma.$disconnect();
});
beforeEach(async () => {
await prisma.user.deleteMany(); // Clean data, NOT connections
});
test('creates user', async () => {
const user = await prisma.user.create({
data: { email: 'test@example.com', name: 'Test' },
});
expect(user.email).toBe('test@example.com');
});
Use single PrismaClient instance across all tests; $disconnect() only in afterAll(); clean database state between tests, not connections.
For Vitest setup configuration (setupFiles, global hooks), see vitest-4/skills/configuring-vitest-4/SKILL.md.
Do NOT disconnect in handlers — breaks warm starts (connection setup every invocation). Use global singleton pattern with connection pooling managed by CLIENT-serverless-config. Exception: RDS Proxy with specific requirements may benefit from explicit $disconnect().
Development: No explicit disconnect needed; Next.js manages lifecycle. Production: Depends on deployment—follow CLIENT-serverless-config for serverless, server pattern for traditional deployment.
| Environment | Config | Output |
|---|---|---|
| Development | log: ['query', 'info', 'warn', 'error'] | Every SQL query with parameters, connection events, warnings/errors |
| Production | `log: ['warn |
', 'error']| Only warnings and errors; reduced log volume, better performance | | **Environment-based** |log: process.env.NODE_ENV === 'production' ? ['warn', 'error'] : ['query', 'info', 'warn', 'error']` | Conditional verbosity |
Custom event handling:
const prisma = new PrismaClient({
log: [
{ emit: 'event', level: 'query' },
{ emit: 'event', level: 'error' },
{ emit: 'stdout', level: 'warn' },
],
});
prisma.$on('query', (e) => {
console.log(`Query: ${e.query} (${e.duration}ms)`);
});
prisma.$on('error', (e) => {
console.error('Prisma Error:', e);
});
MUST:
SHOULD:
NEVER:
Validation:
npm test — expect no "jest/vitest did not exit" warnings, no connection errors| Issue | Cause | Solution |
|---|---|---|
| "jest/vitest did not exit" warning | Missing $disconnect() in afterAll() | Add afterAll(async () => { await prisma.$disconnect() }) |
| "
Too many connections" in tests | New PrismaClient created per test file | Use global singleton pattern (see Vitest setup above) |
| Process hangs on shutdown | Forgot await on $disconnect() | Always await prisma.$disconnect() |
| Serverless cold starts very slow | Disconnecting in handler breaks warm starts | Remove $disconnect() from handler; use connection pooling |
| Connection pool exhausted after shutdown | $disconnect() called before server.close() | Reverse order: close server first, then disconnect |
Express.js: Use server.close() before $disconnect(); handle SIGINT + SIGTERM; add timeout for forced exit.
Fastify: Use onClose hook—framework handles signal listeners and ordering automatically.
NestJS: Implement onModuleDestroy lifecycle hook; use @nestjs/terminus for health checks; automatic cleanup via module system.
Next.js: Dev mode—no explicit disconnect needed. Production—depends on deployment (serverless: see CLIENT-serverless-config; traditional: use server pattern). Server Actions/API Routes—follow serverless pattern.
Serverless (Lambda, Vercel, Cloudflare): Default—do NOT disconnect in handlers. Exception—RDS Proxy with specific config. See CLIENT-serverless-config for connection management.
Test Frameworks: Jest—afterAll() in files or global teardown. Vitest—global setupFiles. Mocha—after() in root suite. Playwright—globalTeardown for E2E.
Next.js Integration:
This skill should be used when the user asks to "create a slash command", "add a command", "write a custom command", "define command arguments", "use command frontmatter", "organize commands", "create command with file references", "interactive command", "use AskUserQuestion in command", or needs guidance on slash command structure, YAML frontmatter fields, dynamic arguments, bash execution in commands, user interaction patterns, or command development best practices for Claude Code.
This skill should be used when the user asks to "create an agent", "add an agent", "write a subagent", "agent frontmatter", "when to use description", "agent examples", "agent tools", "agent colors", "autonomous agent", or needs guidance on agent structure, system prompts, triggering conditions, or agent development best practices for Claude Code plugins.
This skill should be used when the user asks to "create a hook", "add a PreToolUse/PostToolUse/Stop hook", "validate tool use", "implement prompt-based hooks", "use ${CLAUDE_PLUGIN_ROOT}", "set up event-driven automation", "block dangerous commands", or mentions hook events (PreToolUse, PostToolUse, Stop, SubagentStop, SessionStart, SessionEnd, UserPromptSubmit, PreCompact, Notification). Provides comprehensive guidance for creating and implementing Claude Code plugin hooks with focus on advanced prompt-based hooks API.