Environment variables are the standard way to configure Node.js apps differently across development, staging, and production, without hardcoding secrets or environment-specific values into source code.
What Are Environment Variables?
Environment variables are key-value pairs set outside your application code, by the operating system, a hosting platform, or a local .env file, and read at runtime through process.env. This lets the same codebase run with different database URLs, API keys, and settings depending on where it's deployed, without ever committing those values to source control.
During local development, the dotenv package loads variables from a .env file into process.env automatically, so you don't have to export them manually in every terminal session.
// .env file (never committed to git)
// DATABASE_URL=postgres://localhost:5432/myapp
// JWT_SECRET=super-long-random-string
// PORT=3000
import 'dotenv/config';
const port = Number(process.env.PORT) || 3000;
const databaseUrl = process.env.DATABASE_URL;
if (!databaseUrl) {
throw new Error('DATABASE_URL is required');
}
Importing dotenv/config at the very top of your entry file loads .env automatically, before any other code that depends on process.env runs.
Reading Environment Variables
process.env.PORT // always a string, or undefined
Number(process.env.PORT) // convert to a number explicitly
process.env.NODE_ENV === 'production'
Every value in process.env is a string (or undefined), even ones that represent numbers or booleans.
NODE_ENV is a widely used convention for distinguishing development, test, and production behavior.
.env files should never be committed to version control, add them to .gitignore.
Validate required environment variables at startup, failing fast rather than crashing deep inside request handling.
Environment Variables Cheatsheet
Common patterns for working with process.env safely.
Task
Code
Read a variable
process.env.API_KEY
Provide a default
process.env.PORT || 3000
Convert to a number
Number(process.env.PORT)
Convert to a boolean
process.env.DEBUG === 'true'
Load from .env (dev)
import 'dotenv/config';
Check environment
process.env.NODE_ENV === 'production'
Validating Environment Variables at Startup
Rather than discovering a missing environment variable deep inside a request handler in production, validate every required variable once at startup and fail immediately with a clear error message if anything is missing.
const requiredEnvVars = ['DATABASE_URL', 'JWT_SECRET', 'PORT'];
for (const key of requiredEnvVars) {
if (!process.env[key]) {
console.error(`Missing required environment variable: ${key}`);
process.exit(1);
}
}
Failing fast at startup turns a confusing runtime bug into an immediate, obvious deployment failure that's far easier to diagnose.
Per-Environment .env Files
Larger projects sometimes maintain separate files per environment (.env.development, .env.test, .env.production), loading the correct one based on NODE_ENV, while still keeping actual production secrets out of the repository entirely, typically injected by the hosting platform instead.
Common Mistakes
Committing a .env file containing real secrets to version control.
Forgetting that every process.env value is a string, and using it without converting numbers/booleans explicitly.
Not validating required environment variables at startup, causing confusing failures deep in request handling.
Hardcoding fallback secrets directly in code as a "default" for missing environment variables.
Key Takeaways
Environment variables let the same codebase behave differently across environments without code changes.
process.env values are always strings and must be explicitly converted for numbers and booleans.
dotenv loads .env files into process.env for local development convenience.
Validate required environment variables at startup to fail fast with a clear error message.
Pro Tip
Commit a .env.example file (with placeholder values, no real secrets) to your repository. It documents every environment variable your app needs, without exposing anything sensitive, and saves new teammates from hunting through code to find them.
You now manage configuration securely. Next, learn how to test Node.js applications, starting with an overview of testing approaches.