# Serverless Pattern Serverless environments require special handling due to cold starts, connection pooling, and function lifecycle constraints. ## Next.js App Router (Vercel) **File: `lib/prisma.ts`** ```typescript import { PrismaClient } from '@prisma/client' const globalForPrisma = globalThis as unknown as { prisma: PrismaClient | undefined } export const prisma = globalForPrisma.prisma ?? new PrismaClient({ log: process.env.NODE_ENV === 'development' ? ['query', 'error', 'warn'] : ['error'], }) if (process.env.NODE_ENV !== 'production') globalForPrisma.prisma = prisma ``` **Environment Configuration (.env):** ``` DATABASE_URL="postgresql://user:pass@host:5432/db?connection_limit=1&pool_timeout=10" ``` **Why connection_limit=1:** - Each serverless function instance gets ONE connection - Multiple function instances = multiple connections - Prevents pool exhaustion with many concurrent requests - Vercel scales to hundreds of instances automatically **Usage in Server Components:** ```typescript import { prisma } from '@/lib/prisma' export default async function UsersPage() { const users = await prisma.user.findMany() return } ``` **Usage in Server Actions:** ```typescript 'use server' import { prisma } from '@/lib/prisma' export async function createUser(formData: FormData) { const email = formData.get('email') as string return await prisma.user.create({ data: { email } }) } ``` **Usage in Route Handlers:** ```typescript import { NextResponse } from 'next/server' import { prisma } from '@/lib/prisma' export async function GET() { const users = await prisma.user.findMany() return NextResponse.json(users) } ``` **Key Points:** - Never create PrismaClient in component files - Import singleton from `lib/prisma.ts` - Global pattern survives hot reload - Connection limit prevents pool exhaustion --- ## AWS Lambda **File: `lib/db.ts`** ```typescript import { PrismaClient } from '@prisma/client' let prisma: PrismaClient if (!global.prisma) { global.prisma = new PrismaClient({ log: ['error', 'warn'] }) } prisma = global.prisma export default prisma ``` **Lambda Handler:** ```typescript import prisma from './lib/db' export async function handler(event: any) { const users = await prisma.user.findMany() return { statusCode: 200, body: JSON.stringify(users) } } ``` **Environment Variables (Lambda):** ``` DATABASE_URL=postgresql://user:pass@host:5432/db?connection_limit=1&pool_timeout=10&connect_timeout=10 ``` **Lambda-Specific Considerations:** - Lambda reuses container for warm starts - Global singleton survives across invocations - First invocation creates client (cold start) - Subsequent invocations reuse client (warm starts) - No need to disconnect (Lambda freezes container) --- ## Connection Pool Calculation for Serverless **Formula:** ``` max_connections = (max_concurrent_functions * connection_limit) + buffer ``` **Example (Vercel):** - Max concurrent functions: 100 - Connection limit per function: 1 - Buffer: 10 **Result:** Need 110 database connections **Recommended DATABASE_URL for Vercel:** ``` postgresql://user:pass@host:5432/db?connection_limit=1&pool_timeout=10 ``` **Why pool_timeout=10:** - Prevents long waits for connections - Fails fast if pool exhausted - User gets error instead of timeout --- ## Anti-Pattern: Multiple Files Creating Clients **WRONG - Each file creates its own:** **`app/api/users/route.ts`:** ```typescript import { PrismaClient } from '@prisma/client' const prisma = new PrismaClient() export async function GET() { return Response.json(await prisma.user.findMany()) } ``` **`app/api/posts/route.ts`:** ```typescript import { PrismaClient } from '@prisma/client' const prisma = new PrismaClient() export async function GET() { return Response.json(await prisma.post.findMany()) } ``` **Problems in Serverless:** - Each route = separate client = separate pool - 2 routes × 50 function instances × 10 connections = 1000 connections! - Database exhausted under load - P1017 errors inevitable **Fix - Central singleton:** **`lib/prisma.ts`:** ```typescript import { PrismaClient } from '@prisma/client' const globalForPrisma = globalThis as unknown as { prisma: PrismaClient | undefined } export const prisma = globalForPrisma.prisma ?? new PrismaClient() if (process.env.NODE_ENV !== 'production') globalForPrisma.prisma = prisma ``` **`app/api/users/route.ts`:** ```typescript import { prisma } from '@/lib/prisma' export async function GET() { return Response.json(await prisma.user.findMany()) } ``` **`app/api/posts/route.ts`:** ```typescript import { prisma } from '@/lib/prisma' export async function GET() { return Response.json(await prisma.post.findMany()) } ``` **Result:** - 50 function instances × 1 connection = 50 connections - Sustainable and scalable - No P1017 errors