# Connection pooling configured (not new connection per request)

- **Pattern:** `ab-000905` (`database-design-operations.query-patterns.connection-pooling`)
- **Severity:** high
- **Lifecycle:** active
- **Last modified:** 2026-04-18
- **Canonical URL:** https://auditbuffet.com/patterns/ab-000905
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-000905)

## 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.

```ts
// 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
```

```ts
// 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) A `new Pool()` or `new 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: `max` connections 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 `Pool` instance, global Prisma client, or managed pooler). Serverless environments use a serverless-compatible driver or connection pooler. Pool `max` connections is configured.
- **Fail criteria:** `new Client()` or `new 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:

  ```ts
  // 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,
  })
  ```

  ```ts
  // 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
  ```

  ```ts
  // 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
- iso-25010 performance-efficiency.resource-utilization

Taxons: operational-readiness, performance

HTML version: https://auditbuffet.com/patterns/ab-000905
