[{"data":1,"prerenderedAt":362},["ShallowReactive",2],{"blog-how-to/connection-pooling":3},{"id":4,"title":5,"body":6,"category":342,"date":343,"dateModified":344,"description":345,"draft":346,"extension":347,"faq":348,"featured":346,"headerVariant":349,"image":348,"keywords":348,"meta":350,"navigation":351,"ogDescription":352,"ogTitle":348,"path":353,"readTime":348,"schemaOrg":354,"schemaType":355,"seo":356,"sitemap":357,"stem":358,"tags":359,"twitterCard":360,"__hash__":361},"blog/blog/how-to/connection-pooling.md","How to Set Up Database Connection Pooling",{"type":7,"value":8,"toc":326},"minimark",[9,13,17,21,27,30,43,48,51,54,58,81,97,110,123,136,149,162,198,202,223,229,233,238,241,245,248,252,255,259,266,288,307],[10,11],"category-badge",{"category":12},"How-To Guide",[14,15,5],"h1",{"id":16},"how-to-set-up-database-connection-pooling",[18,19,20],"p",{},"Essential for serverless and high-traffic applications",[22,23,24],"tldr",{},[18,25,26],{},"TL;DR (20 minutes):\nUse your database provider's pooler (Supabase, Neon, PlanetScale all have built-in options). For Prisma, enable connection pooling with\n?pgbouncer=true\n. Set pool size to 2-5 connections for serverless, 10-20 for traditional servers. Always handle connection errors and implement retries.",[18,28,29],{},"Prerequisites:",[31,32,33,37,40],"ul",{},[34,35,36],"li",{},"PostgreSQL, MySQL, or similar database",[34,38,39],{},"Understanding of your deployment environment (serverless vs. traditional)",[34,41,42],{},"Database connection string",[44,45,47],"h2",{"id":46},"why-this-matters","Why This Matters",[18,49,50],{},"Database connections are expensive to create. Each connection uses memory, requires authentication, and takes time to establish. Without pooling, serverless functions can exhaust your database's connection limit within seconds during traffic spikes.",[18,52,53],{},"Connection pooling also improves security by centralizing connection management, enabling connection-level monitoring, and reducing the attack surface of your database.",[44,55,57],{"id":56},"step-by-step-guide","Step-by-Step Guide",[59,60,62,67,78],"step",{"number":61},"1",[63,64,66],"h3",{"id":65},"understand-the-problem","Understand the problem",[68,69,74],"pre",{"className":70,"code":72,"language":73},[71],"language-text","// Without pooling - each request creates new connection\nexport async function handler(req) {\n  const client = new Client(connectionString);\n  await client.connect();  // ~50-100ms overhead\n  const result = await client.query('SELECT...');\n  await client.end();\n  return result;\n}\n\n// 100 concurrent requests = 100 connections\n// Most databases allow only 100-500 connections total\n// Result: \"too many connections\" errors\n","text",[75,76,72],"code",{"__ignoreMap":77},"",[18,79,80],{},"Connection pooling reuses existing connections, reducing overhead and preventing exhaustion.",[59,82,84,88,91],{"number":83},"2",[63,85,87],{"id":86},"supabase-connection-pooling","Supabase connection pooling",[18,89,90],{},"Supabase provides built-in connection pooling via Supavisor:",[68,92,95],{"className":93,"code":94,"language":73},[71],"// Direct connection (for migrations, admin tasks)\nDATABASE_URL=\"postgresql://postgres:password@db.xxx.supabase.co:5432/postgres\"\n\n// Pooled connection (for application use) - use port 6543\nDATABASE_URL=\"postgresql://postgres:password@db.xxx.supabase.co:6543/postgres?pgbouncer=true\"\n\n// For Prisma with Supabase\n// schema.prisma\ndatasource db {\n  provider  = \"postgresql\"\n  url       = env(\"DATABASE_URL\")\n  directUrl = env(\"DIRECT_URL\")  // For migrations\n}\n\n// .env\nDATABASE_URL=\"postgresql://...@db.xxx.supabase.co:6543/postgres?pgbouncer=true\"\nDIRECT_URL=\"postgresql://...@db.xxx.supabase.co:5432/postgres\"\n",[75,96,94],{"__ignoreMap":77},[59,98,100,104],{"number":99},"3",[63,101,103],{"id":102},"neon-connection-pooling","Neon connection pooling",[68,105,108],{"className":106,"code":107,"language":73},[71],"// Neon provides built-in pooling\n// Use the pooled connection string from dashboard\n\n// With Prisma\nDATABASE_URL=\"postgresql://user:pass@ep-xxx.us-east-1.aws.neon.tech/mydb?sslmode=require&pgbouncer=true\"\n\n// Neon also supports serverless driver for edge\nimport { neon } from '@neondatabase/serverless';\n\nconst sql = neon(process.env.DATABASE_URL);\nconst result = await sql`SELECT * FROM users WHERE id = ${userId}`;\n",[75,109,107],{"__ignoreMap":77},[59,111,113,117],{"number":112},"4",[63,114,116],{"id":115},"prisma-connection-pooling","Prisma connection pooling",[68,118,121],{"className":119,"code":120,"language":73},[71],"// For serverless (Vercel, Lambda, etc.)\n// prisma/schema.prisma\ngenerator client {\n  provider = \"prisma-client-js\"\n}\n\ndatasource db {\n  provider = \"postgresql\"\n  url      = env(\"DATABASE_URL\")\n}\n\n// Connection management for serverless\nimport { PrismaClient } from '@prisma/client';\n\n// Prevent multiple instances in development\nconst globalForPrisma = globalThis as unknown as {\n  prisma: PrismaClient | undefined\n};\n\nexport const prisma = globalForPrisma.prisma ?? new PrismaClient({\n  log: process.env.NODE_ENV === 'development' ? ['query'] : [],\n});\n\nif (process.env.NODE_ENV !== 'production') {\n  globalForPrisma.prisma = prisma;\n}\n\n// Connection string with pool settings\nDATABASE_URL=\"postgresql://user:pass@host:5432/db?connection_limit=5&pool_timeout=10\"\n",[75,122,120],{"__ignoreMap":77},[59,124,126,130],{"number":125},"5",[63,127,129],{"id":128},"node-postgres-pg-pooling","node-postgres (pg) pooling",[68,131,134],{"className":132,"code":133,"language":73},[71],"import { Pool } from 'pg';\n\n// Create pool (do this once, not per request)\nconst pool = new Pool({\n  connectionString: process.env.DATABASE_URL,\n  max: 10,                    // Maximum connections in pool\n  idleTimeoutMillis: 30000,   // Close idle connections after 30s\n  connectionTimeoutMillis: 5000, // Timeout for new connections\n  maxUses: 7500,              // Close connection after N queries\n});\n\n// Use pool for queries\nexport async function getUser(id) {\n  const client = await pool.connect();\n  try {\n    const result = await client.query(\n      'SELECT * FROM users WHERE id = $1',\n      [id]\n    );\n    return result.rows[0];\n  } finally {\n    client.release();  // Always release back to pool!\n  }\n}\n\n// Or simpler syntax (auto-releases)\nexport async function getUsers() {\n  const result = await pool.query('SELECT * FROM users');\n  return result.rows;\n}\n",[75,135,133],{"__ignoreMap":77},[59,137,139,143],{"number":138},"6",[63,140,142],{"id":141},"pgbouncer-for-self-hosted-databases","PgBouncer for self-hosted databases",[68,144,147],{"className":145,"code":146,"language":73},[71],"# Install PgBouncer\nsudo apt install pgbouncer\n\n# /etc/pgbouncer/pgbouncer.ini\n[databases]\nmydb = host=localhost port=5432 dbname=mydb\n\n[pgbouncer]\nlisten_addr = 0.0.0.0\nlisten_port = 6432\nauth_type = md5\nauth_file = /etc/pgbouncer/userlist.txt\npool_mode = transaction    # Best for web apps\nmax_client_conn = 1000\ndefault_pool_size = 20\nmin_pool_size = 5\nreserve_pool_size = 5\n\n# /etc/pgbouncer/userlist.txt\n\"myuser\" \"md5passwordhash\"\n\n# Connect through PgBouncer\npsql -h localhost -p 6432 -U myuser mydb\n",[75,148,146],{"__ignoreMap":77},[59,150,152,156],{"number":151},"7",[63,153,155],{"id":154},"serverless-specific-configuration","Serverless-specific configuration",[68,157,160],{"className":158,"code":159,"language":73},[71],"// For Vercel Edge Functions / Cloudflare Workers\n// Use HTTP-based database connections\n\n// Neon Serverless Driver\nimport { neon } from '@neondatabase/serverless';\n\nexport const config = { runtime: 'edge' };\n\nexport default async function handler(req) {\n  const sql = neon(process.env.DATABASE_URL);\n  const users = await sql`SELECT * FROM users LIMIT 10`;\n  return Response.json(users);\n}\n\n// PlanetScale Serverless Driver\nimport { connect } from '@planetscale/database';\n\nconst conn = connect({\n  host: process.env.DATABASE_HOST,\n  username: process.env.DATABASE_USERNAME,\n  password: process.env.DATABASE_PASSWORD,\n});\n\nconst results = await conn.execute('SELECT * FROM users');\n",[75,161,159],{"__ignoreMap":77},[163,164,165,168],"warning-box",{},[18,166,167],{},"Pool Sizing Guidelines:",[31,169,170,177,183,189,195],{},[34,171,172,176],{},[173,174,175],"strong",{},"Serverless functions:"," 1-5 connections per function instance",[34,178,179,182],{},[173,180,181],{},"Traditional Node.js server:"," 10-20 connections",[34,184,185,188],{},[173,186,187],{},"Formula:"," connections = (cores * 2) + spindle_count (for traditional DBs)",[34,190,191,194],{},[173,192,193],{},"Never exceed:"," Database max_connections / number_of_app_instances",[34,196,197],{},"Monitor connection usage and adjust based on actual needs",[44,199,201],{"id":200},"how-to-verify-it-worked","How to Verify It Worked",[203,204,205,211,217],"ol",{},[34,206,207,210],{},[173,208,209],{},"Check connection count:"," Monitor active connections in your database",[34,212,213,216],{},[173,214,215],{},"Verify pooling:"," Ensure connections are being reused",[34,218,219,222],{},[173,220,221],{},"Load test:"," Simulate concurrent requests",[68,224,227],{"className":225,"code":226,"language":73},[71],"-- PostgreSQL: Check current connections\nSELECT count(*) FROM pg_stat_activity;\n\n-- See connections by application\nSELECT application_name, count(*)\nFROM pg_stat_activity\nGROUP BY application_name;\n\n-- Check connection states\nSELECT state, count(*)\nFROM pg_stat_activity\nGROUP BY state;\n",[75,228,226],{"__ignoreMap":77},[44,230,232],{"id":231},"common-errors-troubleshooting","Common Errors & Troubleshooting",[234,235,237],"h4",{"id":236},"error-too-many-connections","Error: \"too many connections\"",[18,239,240],{},"Reduce pool size, ensure connections are being released, or use a connection pooler like PgBouncer.",[234,242,244],{"id":243},"error-connection-terminated-unexpectedly","Error: \"connection terminated unexpectedly\"",[18,246,247],{},"Pool timeout or idle connection closed. Add retry logic or adjust idle timeout settings.",[234,249,251],{"id":250},"slow-queries-after-idle-period","Slow queries after idle period",[18,253,254],{},"Connections being re-established. Use min_pool_size to keep some connections warm.",[234,256,258],{"id":257},"prisma-pgbouncer-prepared-statements-error","Prisma + PgBouncer prepared statements error",[18,260,261,262,265],{},"Add ",[75,263,264],{},"?pgbouncer=true"," to your connection string, which disables prepared statements (incompatible with transaction pooling).",[267,268,269,276,282],"faq-section",{},[270,271,273],"faq-item",{"question":272},"Transaction vs. session pooling?",[18,274,275],{},"Transaction pooling (recommended for web apps) assigns a connection per transaction. Session pooling assigns per client session. Transaction mode is more efficient but doesn't support certain features like prepared statements or SET commands.",[270,277,279],{"question":278},"Do I need external pooling if my ORM has built-in pooling?",[18,280,281],{},"For serverless, yes - each function instance creates its own pool. External poolers like PgBouncer or managed database poolers can aggregate connections across all instances.",[270,283,285],{"question":284},"Why are my Vercel functions exhausting connections?",[18,286,287],{},"Each function invocation can create new connections. Use your database provider's pooler, reduce pool size to 1-2, and consider using HTTP-based serverless database drivers.",[18,289,290,293,298,299,298,303],{},[173,291,292],{},"Related guides:",[294,295,297],"a",{"href":296},"/blog/how-to/prisma-security","Prisma Security"," ·\n",[294,300,302],{"href":301},"/blog/how-to/postgresql-roles","PostgreSQL Roles",[294,304,306],{"href":305},"/blog/how-to/database-encryption","Database Encryption",[308,309,310,316,321],"related-articles",{},[311,312],"related-card",{"description":313,"href":314,"title":315},"Step-by-step guide to setting up Firebase Authentication securely. Configure providers, integrate security rules, verify","/blog/how-to/firebase-auth","How to Set Up Firebase Auth Securely",[311,317],{"description":318,"href":319,"title":320},"Complete guide to Firebase Firestore and Realtime Database security rules. Learn rule syntax, common patterns, testing, ","/blog/how-to/firebase-security-rules","How to Write Firebase Security Rules",[311,322],{"description":323,"href":324,"title":325},"Step-by-step guide to secure form validation. Client and server-side validation, CSRF protection, honeypots for bot dete","/blog/how-to/form-validation","How to Implement Secure Form Validation",{"title":77,"searchDepth":327,"depth":327,"links":328},2,[329,330,340,341],{"id":46,"depth":327,"text":47},{"id":56,"depth":327,"text":57,"children":331},[332,334,335,336,337,338,339],{"id":65,"depth":333,"text":66},3,{"id":86,"depth":333,"text":87},{"id":102,"depth":333,"text":103},{"id":115,"depth":333,"text":116},{"id":128,"depth":333,"text":129},{"id":141,"depth":333,"text":142},{"id":154,"depth":333,"text":155},{"id":200,"depth":327,"text":201},{"id":231,"depth":327,"text":232},"how-to","2026-01-09","2026-01-16","Step-by-step guide to database connection pooling. Improve performance and security with PgBouncer, Prisma, and serverless connection management.",false,"md",null,"yellow",{},true,"Optimize database connections for performance and security.","/blog/how-to/connection-pooling","[object Object]","HowTo",{"title":5,"description":345},{"loc":353},"blog/how-to/connection-pooling",[],"summary_large_image","5h2jw5F2XIbS2jdYStYcDRH-CDnv1J1uOtLSCVbZOOI",1775843928747]