Applications and operations

Connect to PostgreSQL from Node.js

Optionally connect from Node.js with pg, a secret connection URL, bounded waits, and deliberate TLS settings.

The application lessons use Node.js as an optional track. You can follow the database and operations lessons without it.

Install the pg driver:

npm install pg

pg (also called node-postgres) is the standard low-level PostgreSQL driver for Node.js. Query builders like Kysely and ORMs like Drizzle sit on top of it, so what you learn here applies even when you add a layer later.

The connection URL

Everything the driver needs fits in one URL:

postgresql://notes_app:password@localhost:5432/notes_app

Read it left to right: role, password, host, port, database. It is the same information you have been giving psql with -U, -h, -p, and -d, packed into a string that fits in one environment variable.

Keep the connection URL in deployment secrets. Do not commit it, print it, or send it to browser code. The password is right there in the string, so treat the whole URL as a credential.

One encoding gotcha: passwords with special characters such as @, :, or # break the URL parsing. Percent-encode them, so p@ss becomes p%40ss. Authentication failures that only happen in production, after someone rotated the password, are this bug more often than not.

Verify the connection

Prove the URL works before building on it:

import pg from 'pg'

const pool = new pg.Pool({
  connectionString: process.env.DATABASE_URL,
})

const result = await pool.query('SELECT current_database(), current_user')
console.log(result.rows[0])
// { current_database: 'notes_app', current_user: 'notes_app' }

await pool.end()

If this prints the wrong database or role, fix it now. If it hangs and then throws ECONNREFUSED, the URL points at a host or port where nothing is listening; recheck host and port against \conninfo from a working psql session.

Hosted databases: two URLs and TLS

A hosted provider may give you separate direct and pooled URLs. The pooled one goes through the provider’s connection pooler and is meant for application traffic; the direct one is for migrations and admin tasks. Use each for its job.

For a remote database, follow the provider’s TLS instructions and verify its certificate. Do not silence certificate errors with rejectUnauthorized: false. That setting disables the check that you are talking to your real database and not an interceptor, which turns your connection encryption into decoration.

Lesson completed

Take this course offline

Get every free book, course edition, and software download.

Get the download library →