The Default Production Database
PostgreSQL
Connect to Postgres from Node, run queries, manage a pool.
What you'll learn
- Use the `pg` driver
- Run parameterized queries
- Set up a connection pool
Postgres is the safe default for production Node apps. Robust, feature-rich, free.
Install
npm install pg Connect
import pg from "pg";
const { Pool } = pg;
const pool = new Pool({
connectionString: process.env.DATABASE_URL,
// postgres://user:pass@host:5432/dbname
});
const { rows } = await pool.query("SELECT NOW()");
console.log(rows[0]); // { now: 2026-05-12... } Always use a pool — never a raw Client per request. Pools reuse connections (opening one is expensive).
Parameterized Queries
const userId = req.params.id;
const { rows } = await pool.query(
"SELECT * FROM users WHERE id = $1",
[userId]
);
const user = rows[0]; $1, $2, … are placeholders. Never string-concat user
input.
Inserts
const { rows } = await pool.query(
`INSERT INTO users (name, email)
VALUES ($1, $2)
RETURNING id, name, email`,
["Ada", "ada@example.com"]
);
console.log(rows[0]); // { id: 42, name: 'Ada', email: '...' } RETURNING is Postgres-specific — gives you the row back.
Transactions
async function transferMoney(from, to, amount) {
const client = await pool.connect();
try {
await client.query("BEGIN");
await client.query("UPDATE accounts SET balance = balance - $1 WHERE id = $2", [amount, from]);
await client.query("UPDATE accounts SET balance = balance + $1 WHERE id = $2", [amount, to]);
await client.query("COMMIT");
} catch (err) {
await client.query("ROLLBACK");
throw err;
} finally {
client.release();
}
} pool.connect() reserves a connection for the duration of the
transaction. Always release it in finally.
Connection String
DATABASE_URL=postgres://username:password@localhost:5432/dbname For production, add ?sslmode=require.
Migrations
Database schema lives in numbered SQL files:
migrations/
0001_initial.sql
0002_add_users_table.sql
0003_add_email_index.sql Tools like node-pg-migrate, dbmate, or your ORM’s built-in
migrator (Drizzle Kit, Prisma) run them in order.
Where to Run Postgres
- Local dev: Docker (
docker run -p 5432:5432 postgres:16) - Production: Neon, Supabase, Railway, RDS, your cloud’s managed DB
Don’t run your own Postgres for a small app. Hosted is cheap and saves headaches.
ORMs →