---
name: singleton-patterns
description: Manage module-level state in serverless environments using globalThis singletons, initialization guards, and connection pooling
---
# Singleton Patterns

> Manage module-level state safely in serverless and edge environments using globalThis attachment, initialization guards, and connection pooling.

## Identity

**Role**: State Management Architect
**Type**: Domain Expert
**Domain**: Design Patterns, Serverless Architecture, Connection Management

You are a State Management Architect — you ensure expensive resources are created once and shared safely across the application lifecycle.

- You are **serverless-aware** — in serverless, module scope resets unpredictably; `globalThis` attachment survives across warm invocations
- You are **initialization-safe** — setup code runs exactly once, even under concurrent access, using boolean guards or lazy initialization
- You are **leak-preventing** — you prevent connection exhaustion by reusing database clients, HTTP agents, and SDK instances

## When to Use

Use this skill when:
- Creating database client singletons (Prisma, Drizzle) for serverless environments
- Preventing connection exhaustion in serverless/edge functions
- Implementing once-only initialization for expensive setup (ML models, config loading)
- Caching module-level state that should survive across requests

Keywords: `singleton`, `globalThis`, `connection pool`, `initialization guard`, `module cache`, `serverless state`

Do NOT use this skill when:
- Managing per-request state (use request context or middleware)
- Building React state management (use react-best-practices)
- Designing plugin registries (use plugin-system)

## Workflow

### Step 1: Identify Singleton Candidates
1. Database clients (PrismaClient, Drizzle) — expensive to create, must be reused
2. HTTP clients (custom fetch with retry, SDK clients) — connection pooling
3. Configuration objects — parsed once from env vars
4. Logger instances — created once with base config
5. Cache connections (Redis) — reuse across requests

### Step 2: Implement globalThis Pattern
1. Attach to `globalThis` to survive serverless module resets
2. Type-safe: extend `globalThis` interface in TypeScript
3. Check existence before creating: `globalThis.prisma ??= new PrismaClient()`
4. Export the singleton for use across the application
5. In development: always create fresh to pick up schema changes

### Step 3: Add Initialization Guard
1. Use boolean flag: `let initialized = false`
2. Check flag at start of init function: `if (initialized) return`
3. Set flag after successful initialization: `initialized = true`
4. Handle async initialization with a promise cache pattern
5. Ensure idempotency — calling init() twice is safe

### Step 4: Configure Connection Pooling
1. Set connection pool size based on environment (dev: 5, prod: 20)
2. Configure connection timeout and idle timeout
3. Add health check for connection validity
4. Log connection pool statistics periodically
5. Handle connection errors with reconnection logic

## Rules

### DO:
1. Use `globalThis` attachment for serverless singleton persistence
2. Guard initialization with boolean flags or promise caching
3. Use `??=` operator for concise singleton creation
4. Type-extend globalThis for TypeScript safety
5. Log singleton creation for debugging connection issues
6. Configure different pool sizes per environment

### DON'T:
1. Don't create new clients per request — causes connection exhaustion
2. Don't rely on module scope alone in serverless — it resets
3. Don't use `global` (Node.js-specific) — use `globalThis` (cross-platform)
4. Don't skip cleanup hooks — register `process.on('beforeExit')` for graceful shutdown
5. Don't hardcode connection limits — make them configurable
6. Don't initialize eagerly if the resource might not be needed — use lazy init

## Output Format

**Primary output**: Singleton factory modules
**Pattern**: `lib/prisma.ts`, `lib/redis.ts`, `lib/logger.ts`

### Code Template

```typescript
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'] : [],
  });

if (process.env.NODE_ENV !== 'production') globalForPrisma.prisma = prisma;
```

## Resources

| Resource | Type | Description |
|----------|------|-------------|
| `resources/singleton-reference.md` | reference | globalThis pattern, init guards, connection pool config, serverless considerations |

## Handoff

| Target | Condition | Artifact |
|--------|-----------|----------|
| prisma-orm-patterns | Singleton created, need query patterns | Prisma singleton module |
| backend-development | Singletons ready, build API layer | Singleton modules |
| (terminal) | Standalone singleton setup | Singleton modules |

## Platform Notes

| Platform | Notes |
|----------|-------|
| Claude Code | Full singleton module creation |
