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
.envfile anddotenvto 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, anddatabasedirectly 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
pg-env/
โโโ package.json
โโโ .env
โโโ .gitignore
โโโ index.js
Installing dotenv
npm install dotenv
Creating a .env File
# .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:
# .gitignore
.env
node_modules/
Loading It at Runtime
// 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();
node index.js
[ { 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
- Build the
pg-envproject above, and confirm the exact output shown. - Add a second variable to
.env(for example,PORT=3000), and read it inindex.jswithprocess.env.PORT. - Confirm
.envis listed in.gitignore, and explain, in one sentence, why it matters. - Change
DATABASE_URLto 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.
dotenvloads a local.envfile intoprocess.envat runtime, always excluded from version control.- A connection string (
postgresql://user:password@host:port/database) packs every connection detail into one value, understood by bothpgand Prisma.
This is the final lesson of this module before exercises. Next module: writing real queries, safely, against this database.