This specification is maintained by the AgentRules Working Group. Have enhancements or want to claim maintainership?Submit Specification →
backendcritical PriorityID: drizzle-038-prepared-statements-pooling-standard

Drizzle ORM 0.38 Prepared Statement Lifecycle & Pool Saturation Guardrails

Enforces strict lifecycle management for Drizzle ORM prepared statements across pooled connections, preventing named-statement collisions and pool exhaustion in relational queries. Requires transaction-scoped execution tokens, explicit error isolation for deterministic rollbacks, and explicit pool exhaustion backpressure policies.

Prohibited Anti-Pattern: Global Unparameterized Prepared Statements Causing PgBouncer Collisions and Connection Pool Starvation

Export Ready-to-Drop Configuration

Select format below to copy code or download file directly.

---
description: Drizzle ORM 0.38 Prepared Statement Lifecycle & Pool Saturation Guardrails - Enforces strict lifecycle management for Drizzle ORM prepared statements across pooled connections, preventing named-statement collisions and pool exhaustion in relational queries. Requires transaction-scoped execution tokens, explicit error isolation for deterministic rollbacks, and explicit pool exhaustion backpressure policies.
globs: src/db/**/*.ts, src/repositories/**/*.ts, src/services/**/*.ts, src/api/**/*.ts
alwaysApply: true
verified_by: "agentrules.org"
license: "CC-BY-4.0"
source: "https://agentrules.org/rules/drizzle-038-prepared-statements-pooling-standard"
---

# Drizzle ORM 0.38 Prepared Statement Lifecycle & Pool Saturation Guardrails

> **Severity**: CRITICAL | **Category**: backend
> **Anti-Pattern Warning**: Global Unparameterized Prepared Statements Causing PgBouncer Collisions and Connection Pool Starvation

## System Constraints
You are a Principal Backend Architect enforcing rock-solid invariants for Drizzle ORM 0.38+. You must prohibit un-scoped named prepared statements in pooled/proxy environments (e.g., PgBouncer transaction mode, AWS RDS Proxy), enforce explicit transaction boundaries with fail-safe rollbacks using tx.rollback(), and mandate proper client-level pool configuration to prevent socket starvation under burst load.

## Strict Guidelines
- Engineers MUST configure connection pool sizing (max, idleTimeoutMillis, connectionTimeoutMillis) explicitly when initializing node-postgres/postgres.js adapters alongside Drizzle.
- Engineers MUST NOT use fixed, global string statement names in .prepare(name) when connecting through transaction-mode connection poolers (PgBouncer, RDS Proxy, Supabase Pooler) to avoid 'prepared statement already exists' fatal collisions.
- Engineers MUST execute all dependent multi-statement mutations inside db.transaction(async (tx) => ...) blocks, using the scoped tx handle instead of the ambient db instance.
- Code MUST explicitly catch known business exceptions and execute tx.rollback() or allow runtime errors to bubble unsuppressed to guarantee database rollback execution.
- Queries compiled via the Drizzle Relational Queries API (db.query.*) MUST NOT be repeatedly compiled inside hot loops without parameterization via sql.placeholder().
- Services MUST configure connection checkout timeouts on underlying pool drivers to fail-fast rather than queuing indefinitely when pool saturation occurs.

## Bad vs Good Implementations
### Safe Prepared Statement and Transaction Lifecycle in Pooled PostgreSQL

#### Bad Antipattern (AI Common Hallucination)
> **Why it fails**: Declaring a globally named prepared statement with a static identifier breaks in transaction-mode proxies (PgBouncer) when queries hit different backend instances or connections reuse the identifier. Additionally, mixing the ambient `db` handle inside `db.transaction()` executes the first mutation outside the atomic boundary, breaking rollback guarantees.
```typescript
import { db } from './db';
import { users, orders } from './schema';
import { eq, sql } from 'drizzle-orm';

// ANTI-PATTERN: Globally named prepared statement collisions in PgBouncer
// and unhandled transaction context leaking mutations outside tx scope
export const getOrderPrepared = db.select()
  .from(orders)
  .where(eq(orders.id, sql.placeholder('orderId')))
  .prepare('get_order'); // Fatal in transaction-mode connection pooling!

export async function checkout(userId: string, orderId: string) {
  // Leaking ambient db call instead of tx handle
  const order = await getOrderPrepared.execute({ orderId });
  
  await db.transaction(async (tx) => {
    await db.update(orders).set({ status: 'paid' }).where(eq(orders.id, orderId));
    // If this fails, the update above is NOT rolled back because it used `db` instead of `tx`
    await tx.update(users).set({ balance: sql`${users.balance} - ${order[0].total}` });
  });
}
```

#### Production Standard (Correct)
> **Standard**: Omitting the fixed prepared statement name enables anonymous prepared statements, completely preventing collision errors across pooled connections. All mutations cleanly invoke the scoped `tx` client, guaranteeing atomic commit and clean rollback upon failure.
```typescript
import { db } from './db';
import { users, orders } from './schema';
import { eq, sql } from 'drizzle-orm';

// PREFERRED: Anonymous prepared statements in pooled architectures or inline parameterized queries
export async function checkout(userId: string, orderId: string, amount: number) {
  return await db.transaction(async (tx) => {
    // Scoped prepared statement without static collision name, bound strictly to the transaction client
    const orderPrepared = tx.select()
      .from(orders)
      .where(eq(orders.id, sql.placeholder('orderId')))
      .prepare(); // Anonymous: safe across all pooling strategies

    const [order] = await orderPrepared.execute({ orderId });
    if (!order) {
      tx.rollback();
    }

    // All mutations strictly bound to transactional handle 'tx'
    await tx.update(orders)
      .set({ status: 'paid' })
      .where(eq(orders.id, orderId));

    await tx.update(users)
      .set({ balance: sql`${users.balance} - ${amount}` })
      .where(eq(users.id, userId));

    return { success: true, orderId };
  });
}
```

Recommended MCP Servers (mcp-serverlist.com)

Equip agent with system tools to verify code for this stack.

Recommended Agent Skills (askills.dev)

Ready-to-use executable skill functions tailored to this stack.

Architectural Specification & Invariant Rationale

Architectural Invariant Design: Drizzle ORM 0.38 Prepared Statement Lifecycle & Pool Saturation Guardrails

Drizzle ORM 0.38 Prepared Statement Lifecycle & Pool Saturation Guardrails defines an industrial-grade behavioral standard for backend engineering. Enforces strict lifecycle management for Drizzle ORM prepared statements across pooled connections, preventing named-statement collisions and pool exhaustion in relational queries. Requires transaction-scoped execution tokens, explicit error isolation for deterministic rollbacks, and explicit pool exhaustion backpressure policies. Modern software architectures require strict adherence to deterministic patterns to guarantee high availability, maintainability, and zero security vulnerabilities.

Framework Paradigm Shift & Drift MechanicsLLMs are trained on millions of open-source repositories containing outdated code, legacy idioms, and unpatched antipatterns. When coding assistants generate implementations for this stack, they default to common statistical tokens: Global Unparameterized Prepared Statements Causing PgBouncer Collisions and Connection Pool Starvation Without an explicit system instruction file, developers spend hours debugging silent failures.
Failure Modes & Production Blast Radius

Hazard Analysis: What Breaks Without This Rule

The following failure modes have been cataloged from hundreds of hours of production code reviews where AI assistants produced non-compliant implementations:

Failure ModeAI Symptom (The Anti-Pattern)SeverityProduction Impact & Remedy
AI Hallucination & Deprecation DriftGlobal Unparameterized Prepared Statements Causing PgBouncer Collisions and Connection Pool StarvationCritical
Violating this industrial standard introduces regression bugs, security risks, and unexpected runtime failures in production.
Enforce explicit behavioral system directives across all AI coding assistants in your repository.
Silent Architecture InconsistencyAI assistants produce mixed paradigms across files, creating fragmented codebase conventions.Medium
Increases cognitive load during code reviews and leads to maintenance debt across engineering teams.
Pin project conventions in .cursor/rules, CLAUDE.md, and AGENTS.md so all team agents follow identical guardrails.
Architectural Directives in Detail

Step-by-Step Production Directives

Each rule constraint below is injected into the AI agent's system prompt to establish deterministic boundaries:

1

Engineers MUST configure connection pool sizing (max, idleTimeoutMillis, connectionTimeoutMillis) explicitly when initializing node-postgres/postgres.js adapters alongside Drizzle.

Engineers MUST configure connection pool sizing (max, idleTimeoutMillis, connectionTimeoutMillis) explicitly when initializing node-postgres/postgres.js adapters alongside Drizzle.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
2

Engineers MUST NOT use fixed, global string statement names in .prepare(name) when connecting through transaction-mode connection poolers (PgBouncer, RDS Proxy, Supabase Pooler) to avoid 'prepared statement already exists' fatal collisions.

Engineers MUST NOT use fixed, global string statement names in .prepare(name) when connecting through transaction-mode connection poolers (PgBouncer, RDS Proxy, Supabase Pooler) to avoid 'prepared statement already exists' fatal collisions.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
3

Engineers MUST execute all dependent multi-statement mutations inside db.transaction(async (tx) => ...) blocks, using the scoped tx handle instead of the ambient db instance.

Engineers MUST execute all dependent multi-statement mutations inside db.transaction(async (tx) => ...) blocks, using the scoped tx handle instead of the ambient db instance.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
4

Code MUST explicitly catch known business exceptions and execute tx.rollback() or allow runtime errors to bubble unsuppressed to guarantee database rollback execution.

Code MUST explicitly catch known business exceptions and execute tx.rollback() or allow runtime errors to bubble unsuppressed to guarantee database rollback execution.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
5

Queries compiled via the Drizzle Relational Queries API (db.query.*) MUST NOT be repeatedly compiled inside hot loops without parameterization via sql.placeholder().

Queries compiled via the Drizzle Relational Queries API (db.query.*) MUST NOT be repeatedly compiled inside hot loops without parameterization via sql.placeholder().

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
6

Services MUST configure connection checkout timeouts on underlying pool drivers to fail-fast rather than queuing indefinitely when pool saturation occurs.

Services MUST configure connection checkout timeouts on underlying pool drivers to fail-fast rather than queuing indefinitely when pool saturation occurs.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
Technical Questions & Answers

Frequently Asked Technical Questions

Common questions developers face when configuring AI coding assistants for this stack:

Q:Why is Drizzle ORM 0.38 Prepared Statement Lifecycle & Pool Saturation Guardrails critical for AI coding assistants?

Enforces strict lifecycle management for Drizzle ORM prepared statements across pooled connections, preventing named-statement collisions and pool exhaustion in relational queries. Requires transaction-scoped execution tokens, explicit error isolation for deterministic rollbacks, and explicit pool exhaustion backpressure policies. Without explicit behavioral boundaries, AI coding assistants (Cursor, Claude Code, Windsurf, Codex) rely on training data averages, which frequently produce deprecated, inefficient, or vulnerable code patterns.

Q:How does adopting this rule prevent AI hallucinations?

This rule explicitly declares what the AI must avoid (Global Unparameterized Prepared Statements Causing PgBouncer Collisions and Connection Pool Starvation) and prescribes verified positive examples. Grounding the LLM with negative and positive pairs eliminates guesswork.

Q:Which AI coding environments are supported?

This specification is multi-platform compatible: Cursor (.cursor/rules/*.mdc & .cursorrules), Anthropic Claude Code (CLAUDE.md), Windsurf (.windsurfrules), Codex / Cline (AGENTS.md), and GitHub Copilot (.github/copilot-instructions.md).

Q:Can I combine this rule with other technology stacks?

Yes. Use the Interactive Stack Builder or download an Agent Pack to merge this rule with other frontend, backend, database, security, and DevOps rules without syntax collision.

Open Specification · CC BY 4.0·Free for Personal, Team & Commercial In-Repo Use

Citation & Open Source Attribution Guidelines

This specification is licensed under Creative Commons Attribution 4.0 International (CC BY 4.0). You are completely free to adapt and share this rule in your workspace. If citing, including in public AI benchmark datasets, or redistributing, attribution to AgentRules.org is required.

1 Rule in Stack

Drizzle