Guides
How to Connect Next.js to PostgreSQL
Server components can query a database directly without a separate API layer in between, which simplifies a lot of app structure — but it also means connection management needs care, especially in serverless deployment environments.
Prerequisites
- arrow_rightA running PostgreSQL database (local, Supabase, or a managed provider)
- arrow_rightA Next.js App Router project
- arrow_rightA database client library (pg, or an ORM like Prisma or Drizzle)
Step 1: Install a Database Client
npm install pg
npm install -D @types/pgStep 2: Set Up a Connection Pool
lib/db.ts
import { Pool } from 'pg';
const pool = new Pool({ connectionString: process.env.DATABASE_URL });
export default pool;A single shared pool instance, not a new connection per request, keeps the database from being overwhelmed as traffic grows.
Step 3: Query From a Server Component
import pool from '@/lib/db';
export default async function ProductsPage() {
const { rows } = await pool.query('SELECT id, name FROM products LIMIT 20');
return (
<ul>{rows.map((p) => <li key={p.id}>{p.name}</li>)}</ul>
);
}Common Errors
- arrow_right"Too many connections" in production — serverless functions can each open their own connection; use connection pooling (PgBouncer, or your provider's built-in pooler) instead of a raw pool per function instance
- arrow_rightQueries work locally but time out in deployment — check that the database allows connections from your deployment platform's IP ranges
- arrow_rightSQL injection risk — always use parameterized queries, never string-concatenate user input into a query
Security Considerations
- arrow_rightAlways use parameterized queries ($1, $2 placeholders), never string interpolation, to prevent SQL injection
- arrow_rightKeep the database connection string in environment variables, never committed to the repository
- arrow_rightUse a database user with only the permissions the application actually needs, not a superuser
Frequently Asked Questions
Should I use a raw SQL client or an ORM?add
An ORM (Prisma, Drizzle) adds type safety and migration tooling that's worth it for most applications; raw SQL via pg gives more direct control and is reasonable for simpler projects or highly specific queries.
How do I handle connections in a serverless deployment?add
Use a connection pooler designed for serverless (like PgBouncer or your provider's managed pooler) rather than a standard connection pool, since serverless functions can spin up many concurrent instances that would otherwise exhaust the database's connection limit.
Can I query the database directly from a client component?add
No — database credentials should never reach the browser. Server components, API routes, or Server Actions are the correct places to query the database.