CodingNic

Connecting Node.js to PostgreSQL

Environment-Based Configuration

Connecting Node.js to PostgreSQL 10 min read

Environment-Based Configuration

Objectives

By the end of this lesson, you should be able to:

  • Explain why database credentials shouldn’t live in source code
  • Use a .env file and dotenv to load configuration at runtime
  • Build a connection string, and use it with pg

๐Ÿ’ก Why this matters: Every example so far hard-coded host, user, password, and database directly into the script, fine for learning, but a real password committed to a real Git repository is a real security problem. This lesson fixes that.

โš ๏ธ A note on verification: every snippet and every result shown below was actually run against a real PostgreSQL server.

Project File Structure

text
pg-env/
โ”œโ”€โ”€ package.json
โ”œโ”€โ”€ .env
โ”œโ”€โ”€ .gitignore
โ””โ”€โ”€ index.js

Installing dotenv

bash
npm install dotenv

Creating a .env File

text
# .env
DATABASE_URL=postgresql://postgres:postgres@localhost:5432/school

A connection string (or “connection URL”) packs host, user, password, port, and database name into one string, following the pattern postgresql://user:password@host:port/database. Both pg and, later, Prisma understand this same format.

.env files hold real secrets, so they must never be committed:

text
# .gitignore
.env
node_modules/

Loading It at Runtime

javascript
// index.js
require('dotenv').config();
const { Pool } = require('pg');

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

async function main() {
  await pool.query('CREATE TABLE IF NOT EXISTS students (id SERIAL PRIMARY KEY, name TEXT NOT NULL)');
  await pool.query("INSERT INTO students (name) VALUES ('Priya')");

  const result = await pool.query('SELECT * FROM students');
  console.log(result.rows);

  await pool.end();
}

main();
bash
node index.js
text
[ { id: 1, name: 'Priya' } ]

require('dotenv').config() reads .env and copies its values into process.env, before anything else in the file runs. connectionString: process.env.DATABASE_URL then hands pg the full connection string instead of four separate fields.

Different Values Per Environment

The real benefit shows up once there’s more than one environment. A local .env might point at a database on localhost, while a production deployment sets DATABASE_URL directly as a real environment variable (through the hosting platform, never a committed file) pointing at a production database. The code in index.js doesn’t change at all, only the value of DATABASE_URL does.

Try It

  1. Build the pg-env project above, and confirm the exact output shown.
  2. Add a second variable to .env (for example, PORT=3000), and read it in index.js with process.env.PORT.
  3. Confirm .env is listed in .gitignore, and explain, in one sentence, why it matters.
  4. Change DATABASE_URL to point at a database that doesn’t exist, and read the resulting connection error.

Recap

  • Database credentials belong in environment variables, not hard-coded in source files.
  • dotenv loads a local .env file into process.env at runtime, always excluded from version control.
  • A connection string (postgresql://user:password@host:port/database) packs every connection detail into one value, understood by both pg and Prisma.

This is the final lesson of this module before exercises. Next module: writing real queries, safely, against this database.