Read environment variables in Node.js
Load and validate environment variables, use .env files deliberately, and keep credentials out of logs and browser bundles.
Read an environment variable through process.env. A missing variable is undefined; an existing variable normally has a string value.
const apiKey = process.env.API_KEY;
if (!apiKey) {
throw new Error('API_KEY is required');
}
console.log('API key configured');
Check that a secret is present without printing its value. Decide explicitly whether an empty string is allowed for each setting.
Supply variables at launch
Use a non-secret setting to try the shell syntax:
# POSIX shell: retained for later child processes
export APP_MODE=development
node app.cjs
# POSIX shell: this command only
APP_MODE=development node app.cjs
$env:APP_MODE = 'development'
node app.cjs
Shell history, process diagnostics, and child-process inheritance can expose environment-delivered secrets. Production credentials should come through an appropriately controlled secret-delivery mechanism.
Load a local .env file
A development file might contain:
APP_MODE=development
DB_URL=postgres://localhost:5432/mydb
Node added --env-file in 20.6:
node --env-file=.env app.cjs
The path is relative to the working directory. Existing process environment values take precedence over values in the file. Check your Node release when using newer parsing features.
For runtimes or projects using dotenv, install it locally and load it before modules read configuration:
require('dotenv').config();
With ESM, initialization order matters; preloading dotenv or using its configuration entry point avoids reading variables before they are loaded. dotenv is a loader, not a file watcher.
Validate once at startup
for (const name of ['API_KEY', 'DB_URL']) {
if (!process.env[name]) throw new Error(`${name} is required`);
}
const rawPort = process.env.PORT ?? '3000';
if (!/^\d+$/.test(rawPort)) throw new Error('PORT must be an integer');
const port = Number(rawPort);
if (!Number.isInteger(port) || port < 1 || port > 65535) {
throw new Error('PORT must be between 1 and 65535');
}
const debug = process.env.DEBUG === 'true';
The string 'false' is truthy, so ordinary boolean coercion is unsuitable for a flag. For settings with more than two accepted values, reject unexpected input rather than silently converting it.
Add secret-bearing .env files to .gitignore and commit a sanitized .env.example. Ignoring a file does not remove an already tracked secret; revoke exposed credentials and address repository history separately.
Changing the file does not update a running process automatically. Restart the application or implement deliberate reload behavior. A browser has no native process.env; values exposed by frontend build tools become client-accessible code. Never put a server secret in a client-exposed variable. Object.keys(process.env) can enumerate names, but avoid dumping the environment into logs.
Contact us
Join the community
to join the community
Try Guance
Start online and pay only for what you use.
Get startedChoose a Guance plan