SDK clients like new Stripe(), new OpenAI(), and new PrismaClient() initialize internal HTTP connection pools, TLS handshake state, and retry logic at construction time. Constructing them inside a request handler means that work — including a TCP connection establishment — happens on every request, adding 20–100ms of latency and preventing connection reuse. For Prisma specifically, constructing a new PrismaClient per request is the documented anti-pattern that causes connection pool exhaustion (each instance opens its own pool of connections, and serverless invocations can open hundreds of pools simultaneously, hitting the database's max_connections limit).
Low because per-request SDK construction primarily causes latency degradation and connection pool waste rather than immediate data loss or financial exposure.
Move SDK construction to module scope in a dedicated singleton file. Export the instance, not the class. In src/lib/stripe.ts:
import Stripe from 'stripe'
// Constructed once when the module is first imported
export const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, {
apiVersion: '2025-01-27.acacia',
timeout: 10000,
})
For Prisma in a serverless environment, use the globalThis singleton pattern from the Prisma docs to avoid creating multiple instances across hot-reload cycles in development:
import { PrismaClient } from '@prisma/client'
const globalForPrisma = globalThis as unknown as { prisma: PrismaClient }
export const prisma = globalForPrisma.prisma ?? new PrismaClient()
if (process.env.NODE_ENV !== 'production') globalForPrisma.prisma = prisma
ID: ai-slop-cost-bombs.cache-idempotency.third-party-sdk-singleton
Severity: low
What to look for: Walk source files for new constructor calls of third-party SDK clients: new Stripe(, new OpenAI(, new Anthropic(, new Resend(, new Twilio(, new S3Client(, new PrismaClient(. Count all per-library construction sites and verify each library is constructed at most once at module scope (not inside a request handler).
Pass criteria: Each third-party SDK is constructed exactly 1 time at module scope. Report: "X SDK construction sites inspected, Y singleton, 0 per-request."
Fail criteria: At least 1 SDK is constructed inside a request handler (re-created per request).
Skip (N/A) when: No third-party SDK construction calls found in source.
Detail on fail: "1 per-request SDK construction: app/api/checkout/route.ts calls new Stripe(...) inside the POST handler — every request initializes a new HTTP agent and connection pool"
Remediation: SDK clients are designed to be reused — constructing them per-request defeats their internal connection pooling. Move construction to module scope:
// Bad: per-request
export async function POST(req: Request) {
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!)
// ...
}
// Good: module-scope singleton
import Stripe from 'stripe'
export const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!)
// Then in route:
import { stripe } from '@/lib/stripe'
export async function POST(req: Request) {
// ... use the shared instance
}