Master Code
On The Go

Learn. Practice. Build.

Home › How-To › Node.js with PostgreSQL

Node.js Guide

Node.js with PostgreSQL

The most common Node.js database pairing. Here's how to connect, query, and scale with either raw SQL (pg) or an ORM (Prisma).

Quick answer: Install pg for raw SQL — fast, lightweight, full control. Or use Prisma for a type-safe schema-first approach — more setup but better DX for larger apps.

1

Install pg (node-postgres)

npm install pg dotenv

Add your connection string to .env:

DATABASE_URL=postgres://user:password@localhost:5432/mydb
2

Create a Connection Pool

import 'dotenv/config';
import pg from 'pg';

const { Pool } = pg;

export const pool = new Pool({
    connectionString: process.env.DATABASE_URL,
    max: 20,                  // max connections in pool
    idleTimeoutMillis: 30000, // close idle connections after 30s
    connectionTimeoutMillis: 2000  // fail fast if no connection
});

// Test the connection on startup
pool.on('error', (err) => {
    console.error('Unexpected pool error:', err);
});

Always use a pool, never a single Client, in web servers. A Client opens a new connection per request — slow and resource-hungry.

3

Run Your First Query

import { pool } from './db.js';

const result = await pool.query('SELECT NOW() as now');
console.log(result.rows[0].now);
// 2026-10-05T12:00:00.000Z

Create a table and insert data:

await pool.query(`
    CREATE TABLE IF NOT EXISTS users (
        id SERIAL PRIMARY KEY,
        name TEXT NOT NULL,
        email TEXT UNIQUE NOT NULL,
        created_at TIMESTAMPTZ DEFAULT NOW()
    )
`);

const insert = await pool.query(
    'INSERT INTO users (name, email) VALUES ($1, $2) RETURNING id, name',
    ['Sarah', 'sarah@example.com']
);

console.log(insert.rows[0]); // { id: 1, name: 'Sarah' }

Always use parameterized queries. $1, $2 placeholders prevent SQL injection. Never concatenate user input into SQL strings.

4

CRUD Operations

// READ all
const all = await pool.query('SELECT * FROM users ORDER BY created_at DESC');

// READ one
const one = await pool.query('SELECT * FROM users WHERE id = $1', [userId]);

// UPDATE
await pool.query(
    'UPDATE users SET name = $1 WHERE id = $2',
    ['Sarah Updated', userId]
);

// DELETE
await pool.query('DELETE FROM users WHERE id = $1', [userId]);
5

Transactions

const client = await pool.connect();
try {
    await client.query('BEGIN');

    await client.query(
        'INSERT INTO accounts (name, balance) VALUES ($1, $2)',
        ['Sarah', 100]
    );
    await client.query(
        'UPDATE accounts SET balance = balance - 50 WHERE name = $1',
        ['Sarah']
    );

    await client.query('COMMIT');
} catch (err) {
    await client.query('ROLLBACK');
    throw err;
} finally {
    client.release();  // ALWAYS return to pool
}

Use transactions when multiple queries must all succeed or all fail (transfers, orders, etc.).

6

Alternative — Prisma ORM

If you prefer type safety and migrations over raw SQL:

npm install prisma @prisma/client
npx prisma init

Define your schema in prisma/schema.prisma:

model User {
    id        Int      @id @default(autoincrement())
    name      String
    email     String   @unique
    createdAt DateTime @default(now())
}

Run migrations and query:

npx prisma migrate dev --name init

// Then in code:
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient();

const users = await prisma.user.findMany();
const user = await prisma.user.create({
    data: { name: 'Sarah', email: 'sarah@example.com' }
});

⚖️ pg vs Prisma — Quick Comparison

🛡️ Production Best Practices

❓ Frequently Asked Questions

How do I connect Node.js to PostgreSQL?

Install pg, create a Pool with your connection string, use pool.query for SQL. Always parameterize queries.

pg or Prisma?

pg for raw SQL control and small apps. Prisma for type safety, migrations, and team projects.

What is a connection pool?

A set of reusable database connections. Reusing connections is much faster than opening new ones per query.

How do I prevent SQL injection?

Use parameterized queries with $1, $2 placeholders. Pass values in an array. Never concatenate strings.

🎯 What's Next?

← All How-To Guides