Initial commit

This commit is contained in:
Zhongwei Li
2025-11-29 18:22:25 +08:00
commit c3294f28aa
60 changed files with 10297 additions and 0 deletions

View File

@@ -0,0 +1,163 @@
---
name: configuring-serverless-clients
description: Configure PrismaClient for serverless (Next.js, Lambda, Vercel) with connection_limit=1 and global singleton pattern.
allowed-tools: Read, Write, Edit, Glob, Grep
---
# Serverless PrismaClient Configuration
Configure PrismaClient for serverless platforms to prevent connection pool exhaustion using connection limits and global singleton patterns.
## Activation Triggers
Deploy to Next.js (App/Pages Router), AWS Lambda, Vercel, or similar serverless platforms; encountering P1017 errors; files in app/, pages/api/, lambda/ directories.
## Problem & Solution
**Problem:** Each Lambda instance creates its own connection pool. Default unlimited pool × instances exhausts database (e.g., 10 instances × 10 connections = 100 connections).
**Solution:** Set `connection_limit=1` in DATABASE_URL; use global singleton to reuse client across invocations; consider PgBouncer for high concurrency.
## Configuration Workflow
**Phase 1—Environment:** Add `connection_limit=1` and `pool_timeout=20` to DATABASE_URL in .env; configure in Vercel dashboard if applicable.
**Phase 2—Client Singleton:** Create single global PrismaClient in `lib/prisma.ts`; use `globalThis` pattern (Next.js 13+ App Router), `global.prisma` pattern (Pages Router/Lambda), or initialize outside handler (Lambda standalone).
**Phase 3—Validation:** Verify DATABASE_URL contains connection parameters; confirm `new PrismaClient()` appears only in `lib/prisma.ts`; test with 10+ concurrent requests; monitor connection count.
## Implementation Patterns
### Next.js App Router (`lib/prisma.ts`)
```typescript
import { PrismaClient } from '@prisma/client';
const prismaClientSingleton = () => new PrismaClient();
declare const globalThis: {
prismaGlobal: ReturnType<typeof prismaClientSingleton>;
} & typeof global;
const prisma = globalThis.prismaGlobal ?? prismaClientSingleton();
export default prisma;
if (process.env.NODE_ENV !== 'production') globalThis.prismaGlobal = prisma;
```
**Environment:** `DATABASE_URL="postgresql://user:pass@host:5432/db?connection_limit=1&pool_timeout=20"`
**Usage in Server Action:**
```typescript
import prisma from '@/lib/prisma';
export async function createUser(formData: FormData) {
'use server';
return await prisma.user.create({
data: {
email: formData.get('email') as string,
name: formData.get('name') as string,
},
});
}
```
### Next.js Pages Router / AWS Lambda (`lib/prisma.ts`)
```typescript
import { PrismaClient } from '@prisma/client';
declare global {
var prisma: PrismaClient | undefined;
}
const prisma = global.prisma || new PrismaClient();
if (process.env.NODE_ENV !== 'production') global.prisma = prisma;
export default prisma;
```
**Lambda Handler:**
```typescript
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient();
export const handler = async (event: any) => {
const users = await prisma.user.findMany();
return { statusCode: 200, body: JSON.stringify(users) };
// Never call prisma.$disconnect() reuse Lambda container connections
};
```
### With PgBouncer (High Concurrency)
Use when >50
concurrent requests or connection limits still cause issues.
```bash
DATABASE_URL="postgresql://user:pass@pgbouncer-host:6543/db?connection_limit=10&pool_timeout=20"
DIRECT_URL="postgresql://user:pass@direct-host:5432/db"
```
```prisma
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
directUrl = env("DIRECT_URL")
}
```
DATABASE_URL → PgBouncer (queries); DIRECT_URL → database (migrations).
## Requirements
**MUST:** Set `connection_limit=1` in DATABASE_URL; use global singleton (never `new PrismaClient()` in functions); create single `lib/prisma.ts` imported throughout; add `pool_timeout`.
**SHOULD:** Use PgBouncer for high concurrency (>50); monitor production connection count; set limit via URL parameter; reuse Lambda connections.
**NEVER:** Create `new PrismaClient()` in routes/handlers; use default pool size in serverless; call `$disconnect()` in handlers; deploy without limits; split instances across files.
## Common Mistakes
| Issue | Wrong | Right |
| ------------------------------ | --------------------------------------------------------- | ------------------------------------------ |
| Connection in Constructor | `new PrismaClient({ datasources: { db: { url: ... } } })` | Set `connection_limit=1` in DATABASE_URL |
| Multiple Instances | `const prisma = new PrismaClient()` inside functions | Import singleton from `lib/prisma` |
| Handler Disconnect | `await prisma.$disconnect()` after query | Remove disconnect reuse containers |
| Missing TypeScript Declaration | `const prisma = global.prisma \|\| ...` | `declare global { var prisma: ... }` first |
## Validation Checklist
1. **Environment:** DATABASE_URL contains `connection_limit=1` and `pool_timeout`; verified in Vercel dashboard.
2. **Code:** `new PrismaClient()` appears exactly once in `lib/prisma.ts`; all other files import from it.
3. **Testing:** 10+ concurrent requests to staging; connection count stays ≤10-15; no P1017 errors.
4. **Monitoring:** Production alerts for connection exhaustion and timeout errors.
## Platform-Specific Notes
**Vercel:** Set environment variables in dashboard (
auto-encrypted); connection pooling shared across invocations; consider Vercel Postgres for built-in pooling.
**AWS Lambda:** Container reuse varies by traffic; cold starts create new instances; use provisioned concurrency for consistency; Lambda layers optimize Prisma binary size.
**Cloudflare Workers:** Standard PrismaClient unsupported (V8 isolates, not Node.js); use Data Proxy or D1.
**Railway/Render:** Apply `connection_limit=1` pattern; check platform docs for built-in pooling.
## Related Skills
**Next.js Integration:**
- If implementing authenticated data access layers in Next.js, use the securing-data-access-layer skill from nextjs-16 for verifySession() DAL patterns
- If securing server actions with database operations, use the securing-server-actions skill from nextjs-16 for authentication patterns
## References
- Next.js patterns: `references/nextjs-patterns.md`
- Lambda optimization: `references/lambda-patterns.md`
- PgBouncer setup: `references/pgbouncer-guide.md`