Connection Pooling

beginner*

Database connection pooling for serverless and edge environments. Prevents connection exhaustion and handles cold starts gracefully.

databaseprismaserverlessedgepostgresql
Tested on201619TS5.9
$ bunx sinew add database/connection-pooling
Interactive demo coming soon

Prerequisites

  • PostgreSQL14+

    Or any Prisma-supported database

Tested With

3/3 passing
Next.js15.0
Next.js14.2
Prisma6.0

Related Patterns

Extends

Works well with

1The Problem

In traditional server environments, you maintain a pool of database connections that get reused across requests. In serverless:

  • Each function invocation might create a new connection
  • Cold starts create fresh connections
  • Connections aren't shared across function instances
  • You can easily hit PostgreSQL's default 100 connection limit

2The Solution

Use a connection pooler like PgBouncer or Prisma Accelerate to manage connections externally.

3Files

lib/db.ts

lib/db.tsTypeScript
import { PrismaClient } from "@prisma/client";

const globalForPrisma = globalThis as unknown as {
  prisma: PrismaClient | undefined;
};

export const prisma =
  globalForPrisma.prisma ??
  new PrismaClient({
    log: process.env.NODE_ENV === "development" ? ["query", "error", "warn"] : ["error"],
  });

if (process.env.NODE_ENV !== "production") {
  globalForPrisma.prisma = prisma;
}

lib/db-edge.ts

lib/db-edge.tsTypeScript
import { PrismaClient } from "@prisma/client/edge";
import { withAccelerate } from "@prisma/extension-accelerate";

export const prisma = new PrismaClient().$extends(withAccelerate());

prisma/schema.prisma

prisma/schema.prismaprisma
generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider  = "postgresql"
  url       = env("DATABASE_URL")
  directUrl = env("DIRECT_URL")
}

model User {
  id        String   @id @default(cuid())
  email     String   @unique
  name      String?
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
}

.env.example

.env.exampleBash
# Pooled connection (use for application)
DATABASE_URL="postgresql://user:password@pooler.example.com:6543/mydb?pgbouncer=true"

# Direct connection (use for migrations)
DIRECT_URL="postgresql://user:password@db.example.com:5432/mydb"

4Dependencies

$ bun add @prisma/client
$ bun add -D prisma

5Configuration

Environment Variables

| Variable | Description | | -------------- | -------------------------------------------------- | | DATABASE_URL | Pooled connection string for your application | | DIRECT_URL | Direct connection for migrations and introspection |

Connection String Parameters

Add these to your pooled connection string:

  • pgbouncer=true - Enables PgBouncer compatibility mode
  • connection_limit=1 - Limits connections per serverless instance

6Usage

// In your API routes or server components
import { prisma } from "@/lib/db";

export async function getUsers() {
  return prisma.user.findMany();
}
TypeScript

7Troubleshooting

"Too many connections" error

You're hitting your database connection limit. Solutions:

  1. Use a connection pooler (PgBouncer, Prisma Accelerate, Supavisor)
  2. Reduce connection_limit in your connection string
  3. Increase your database's max connections (if self-hosted)

Slow cold starts

The Prisma Client initialization adds ~200-500ms to cold starts. Mitigations:

  1. Use Prisma Accelerate for edge caching
  2. Keep functions warm with scheduled pings
  3. Use smaller Prisma Client bundles with output configuration

8Edge Runtime

For edge functions (Vercel Edge, Cloudflare Workers), use the edge client with Accelerate:

import { prisma } from "@/lib/db-edge";

export const runtime = "edge";

export async function GET() {
  const users = await prisma.user.findMany({
    cacheStrategy: { ttl: 60 }, // Cache for 60 seconds
  });
  return Response.json(users);
}
TypeScript

Related patterns