Connection Reuse in Development

The Hot Reload Problem

In next dev, files are re-evaluated on every change. If lib/prisma.ts does new PrismaClient() at the top level, each reload opens a new connection pool, and soon PostgreSQL says "too many clients already". The fix: store the client on globalThis, which survives reloads.

lib/prisma.ts

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'] : ['error'] });

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

Why It Works

Example

Simulate three hot reloads of the module. Without the global, each reload creates a new pool:

class Pool {
  static created = 0;
  readonly id = ++Pool.created;
}

const g = globalThis as unknown as { pool?: Pool };

function loadModuleNaive(): Pool {
  return new Pool();
}
function loadModuleWithGlobal(): Pool {
  const pool = g.pool ?? new Pool();
  g.pool = pool;
  return pool;
}

for (let i = 1; i <= 3; i++) loadModuleNaive();
console.log('naive: pools created =', Pool.created);

Pool.created = 0;
const ids = [1, 2, 3].map(() => loadModuleWithGlobal().id);
console.log('global: pool ids =', ids.join(', '), '| pools created =', Pool.created);

Output

naive: pools created = 3
global: pool ids = 1, 1, 1 | pools created = 1

Serverless and Edge

  • On serverless platforms each function instance has its own pool. Use a pooler (PgBouncer, Prisma Accelerate, Neon/Supabase pooled URL) so hundreds of instances do not exhaust the database.
  • Prisma needs the Node.js runtime unless you use a driver adapter. Keep database pages on runtime = 'nodejs' (the default).