Connection pooling configured (not new connection per request)
Why it matters
Creating a new database connection per request exhausts the Postgres connection limit in minutes under load. Postgres allows roughly 100 connections by default (adjustable but resource-constrained); a serverless function that opens a new PrismaClient() or new Pool() per invocation can exhaust this from a single spike of concurrent requests, producing too many connections errors for all users. CWE-400 (uncontrolled resource consumption) applies directly: connection handles are a finite resource, and unbounded creation degrades the service for all tenants. ISO 25010 resource-utilisation captures the connection efficiency requirement.
Severity rationale
High because new-connection-per-request exhausts the Postgres connection limit rapidly under moderate concurrency, producing hard failures for all users rather than degraded performance.
Remediation
Use a module-level singleton pool or the Prisma global singleton pattern so one pool instance is shared across all request handlers. For serverless deployments, use a serverless-compatible driver or connection pooler.
// lib/prisma.ts — Next.js singleton (prevents hot-reload exhaustion)
import { PrismaClient } from '@prisma/client'
const g = globalThis as { prisma?: PrismaClient }
export const prisma = g.prisma ?? new PrismaClient()
if (process.env.NODE_ENV !== 'production') g.prisma = prisma
// lib/db.ts — pg Pool singleton for long-running servers
import { Pool } from 'pg'
export const pool = new Pool({
connectionString: process.env.DATABASE_URL,
max: 20,
idleTimeoutMillis: 30_000,
})
For Neon or Supabase on Vercel Edge, use the serverless HTTP driver (@neondatabase/serverless) instead of a persistent pool — HTTP-per-query is correct for stateless edge runtimes.
Detection
-
ID:
connection-pooling -
Severity:
high -
What to look for: Count every database client or connection initialization point in the codebase. Read the database setup file (
src/db/index.ts,src/lib/db.ts,src/lib/prisma.ts,lib/db/client.ts, or similar). Enumerate every backup mechanism configured and check whether: (1) Anew Pool()ornew Client()is created inside a request handler (wrong — creates a new connection per request). (2) A module-level singleton is used (correct — one pool shared across requests). (3) For Prisma in serverless environments (Vercel, Netlify, Cloudflare), check for the global singleton pattern to prevent connection exhaustion from module re-instantiation in hot-reload or concurrent executions. (4) For serverless databases (Neon, PlanetScale, Supabase), check if the serverless-compatible driver is used (@neondatabase/serverless, Supabase connection pooler on port 6543). Check connection pool configuration:maxconnections should be set appropriately (not unlimited, not too restrictive). -
Pass criteria: Database connection uses a singleton pool — at least 1 pool instance shared across all request handlers (module-level
Poolinstance, global Prisma client, or managed pooler). Serverless environments use a serverless-compatible driver or connection pooler. Poolmaxconnections is configured. -
Fail criteria:
new Client()ornew Pool()created inside a request handler function.new PrismaClient()instantiated on every request without the global singleton pattern. No pooling for a serverless deployment that makes concurrent requests. -
Skip (N/A) when: Application uses a fully managed database client that handles pooling internally and requires no configuration (e.g., Supabase JS client for browser-side queries via the Supabase API layer, Firebase SDK).
-
Detail on fail: Specify the file and pattern. Example:
"In src/app/api/users/route.ts: new Pool() created inside the GET handler — a new connection is opened for every request."or"lib/prisma.ts creates new PrismaClient() without global singleton pattern — connection exhaustion likely in serverless hot-reload.". -
Remediation: Use a singleton pool:
// lib/db.ts — singleton pg Pool (long-running server) import { Pool } from 'pg' export const pool = new Pool({ connectionString: process.env.DATABASE_URL, max: 20, // maximum connections in pool idleTimeoutMillis: 30000, connectionTimeoutMillis: 2000, })// lib/prisma.ts — Prisma singleton for serverless (Next.js) import { PrismaClient } from '@prisma/client' const globalForPrisma = globalThis as unknown as { prisma: PrismaClient } export const prisma = globalForPrisma.prisma ?? new PrismaClient({ log: process.env.NODE_ENV === 'development' ? ['query', 'warn', 'error'] : ['warn', 'error'], }) if (process.env.NODE_ENV !== 'production') globalForPrisma.prisma = prisma// For Neon serverless (Vercel Edge/Cloudflare Workers) import { neon } from '@neondatabase/serverless' const sql = neon(process.env.DATABASE_URL!) // sql is a function — no persistent connection, uses HTTP for each query // Appropriate for edge runtimes; use pg Pool for Node.js runtimes
External references
- cwe · CWE-400 — Uncontrolled Resource Consumption
- iso-25010:2011 · performance-efficiency.resource-utilization — Resource Utilisation
Taxons
History
- 2026-04-18·v1.0.0·Initial import from database-design-operations·automated