# Third-party SDK clients are constructed once (singleton)

- **Pattern:** `ab-000253` (`ai-slop-cost-bombs.cache-idempotency.third-party-sdk-singleton`)
- **Severity:** low
- **Lifecycle:** active
- **Last modified:** 2026-04-18
- **Canonical URL:** https://auditbuffet.com/patterns/ab-000253
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-000253)

## Why it matters

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

## Severity rationale

Low because per-request SDK construction primarily causes latency degradation and connection pool waste rather than immediate data loss or financial exposure.

## Remediation

Move SDK construction to module scope in a dedicated singleton file. Export the instance, not the class. In `src/lib/stripe.ts`:

```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:

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

## Detection

- **ID:** `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:

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

## External references

- iso-25010 performance-efficiency

Taxons: cost-efficiency, performance

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