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/pg

Step 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.

BUILDING SOMETHING SIMILAR?

If you'd rather have this built and shipped than build it yourself, I'm available for freelance and contract work.