Use dotenv package to load .env file into process.env. Install: npm install dotenv. Load at application entry: require('dotenv').config() as first line in index.js. Create .env file: DATABASE_URL=postgres://localhost/mydb, API_KEY=secret123, PORT=3000. Access: const dbUrl = process.env.DATABASE_URL. Add .env to .gitignore (never commit secrets). Create .env.example with dummy values: DATABASE_URL=your_db_url_here, API_KEY=your_api_key. Benefits: Keeps secrets out of code, easy to change without code changes, different values per environment. Only use in development - production uses platform environment variables (AWS, Heroku, Azure). Node.js v20.6+ native support: node --env-file=.env app.js (no dotenv package needed).
Node.js Environment Config FAQ & Answers
10 expert Node.js Environment Config answers researched from official documentation. Every answer cites authoritative sources you can verify.
unknown
10 questionsNEVER use .env files in production. Set environment variables directly in hosting platform or use secrets manager. Platform configuration: AWS Elastic Beanstalk (environment properties), Heroku (heroku config:set KEY=value), Azure App Service (application settings), Docker (docker run -e KEY=value), Kubernetes (ConfigMap for non-secrets, Secret for sensitive). Secrets managers (high security): AWS Secrets Manager, Azure Key Vault, HashiCorp Vault. Load secrets at startup: const AWS = require('aws-sdk'); const secrets = await secretsManager.getSecretValue({SecretId: 'prod/api'}).promise(). Benefits: Centralized management, rotation without redeploy, audit logging, encryption at rest. CI/CD: Inject variables during deploy, store in GitHub Secrets / GitLab CI Variables. Never: Hardcode secrets, commit .env to git, store in Docker images.
NODE_ENV=production enables critical performance optimizations in Node.js frameworks. Effects in Express: (1) View template caching (compiles once, not per request), (2) CSS caching, (3) Less verbose error messages (no stack traces to users), (4) ~3x performance improvement. Effects in other frameworks: React builds optimized bundles, webpack minifies code, logging libraries reduce verbosity. Set in production: export NODE_ENV=production in shell, or in platform config (Heroku, AWS). Check: if (process.env.NODE_ENV === 'production') {/* production logic */}. Default: If not set, defaults to development or undefined (framework-dependent). Always set explicitly in production deployments. Common values: 'development', 'production', 'test' (for testing). Never: Mix development and production configs in same deployment.
Validate all required variables at startup, fail fast if missing. Pattern: function validateEnv() {const required = ['DATABASE_URL', 'API_KEY', 'JWT_SECRET']; const missing = required.filter(key => !process.env[key]); if (missing.length) {console.error(Missing required env vars: ${missing.join(', ')}); process.exit(1);}} validateEnv(). Call before app initialization. Advanced: Use envalid library for type conversion and validation: const {cleanEnv, str, port} = require('envalid'); const env = cleanEnv(process.env, {DATABASE_URL: str(), PORT: port({default: 3000}), API_KEY: str()}). Provides: Type checking (port numbers, URLs, emails), default values, automatic documentation. Benefits: Catch configuration errors before deploy, clear error messages, prevents runtime failures from missing config. Document all variables in README or .env.example.
YES, create centralized config module that maps environment variables to typed config object. Pattern: Create config.js: module.exports = {database: {url: process.env.DATABASE_URL, pool: {min: parseInt(process.env.DB_POOL_MIN) || 2, max: parseInt(process.env.DB_POOL_MAX) || 10}}, api: {key: process.env.API_KEY, timeout: parseInt(process.env.API_TIMEOUT) || 5000}, server: {port: parseInt(process.env.PORT) || 3000, nodeEnv: process.env.NODE_ENV || 'development'}}. Benefits: (1) Single import: const config = require('./config'), (2) Type conversion (string to number), (3) Default values, (4) Validation in one place, (5) Easy to test (mock config object). Usage: app.listen(config.server.port) instead of process.env.PORT. Better than accessing process.env.* throughout codebase (scattered, no defaults, no types).
Use dotenv package to load .env file into process.env. Install: npm install dotenv. Load at application entry: require('dotenv').config() as first line in index.js. Create .env file: DATABASE_URL=postgres://localhost/mydb, API_KEY=secret123, PORT=3000. Access: const dbUrl = process.env.DATABASE_URL. Add .env to .gitignore (never commit secrets). Create .env.example with dummy values: DATABASE_URL=your_db_url_here, API_KEY=your_api_key. Benefits: Keeps secrets out of code, easy to change without code changes, different values per environment. Only use in development - production uses platform environment variables (AWS, Heroku, Azure). Node.js v20.6+ native support: node --env-file=.env app.js (no dotenv package needed).
NEVER use .env files in production. Set environment variables directly in hosting platform or use secrets manager. Platform configuration: AWS Elastic Beanstalk (environment properties), Heroku (heroku config:set KEY=value), Azure App Service (application settings), Docker (docker run -e KEY=value), Kubernetes (ConfigMap for non-secrets, Secret for sensitive). Secrets managers (high security): AWS Secrets Manager, Azure Key Vault, HashiCorp Vault. Load secrets at startup: const AWS = require('aws-sdk'); const secrets = await secretsManager.getSecretValue({SecretId: 'prod/api'}).promise(). Benefits: Centralized management, rotation without redeploy, audit logging, encryption at rest. CI/CD: Inject variables during deploy, store in GitHub Secrets / GitLab CI Variables. Never: Hardcode secrets, commit .env to git, store in Docker images.
NODE_ENV=production enables critical performance optimizations in Node.js frameworks. Effects in Express: (1) View template caching (compiles once, not per request), (2) CSS caching, (3) Less verbose error messages (no stack traces to users), (4) ~3x performance improvement. Effects in other frameworks: React builds optimized bundles, webpack minifies code, logging libraries reduce verbosity. Set in production: export NODE_ENV=production in shell, or in platform config (Heroku, AWS). Check: if (process.env.NODE_ENV === 'production') {/* production logic */}. Default: If not set, defaults to development or undefined (framework-dependent). Always set explicitly in production deployments. Common values: 'development', 'production', 'test' (for testing). Never: Mix development and production configs in same deployment.
Validate all required variables at startup, fail fast if missing. Pattern: function validateEnv() {const required = ['DATABASE_URL', 'API_KEY', 'JWT_SECRET']; const missing = required.filter(key => !process.env[key]); if (missing.length) {console.error(Missing required env vars: ${missing.join(', ')}); process.exit(1);}} validateEnv(). Call before app initialization. Advanced: Use envalid library for type conversion and validation: const {cleanEnv, str, port} = require('envalid'); const env = cleanEnv(process.env, {DATABASE_URL: str(), PORT: port({default: 3000}), API_KEY: str()}). Provides: Type checking (port numbers, URLs, emails), default values, automatic documentation. Benefits: Catch configuration errors before deploy, clear error messages, prevents runtime failures from missing config. Document all variables in README or .env.example.
YES, create centralized config module that maps environment variables to typed config object. Pattern: Create config.js: module.exports = {database: {url: process.env.DATABASE_URL, pool: {min: parseInt(process.env.DB_POOL_MIN) || 2, max: parseInt(process.env.DB_POOL_MAX) || 10}}, api: {key: process.env.API_KEY, timeout: parseInt(process.env.API_TIMEOUT) || 5000}, server: {port: parseInt(process.env.PORT) || 3000, nodeEnv: process.env.NODE_ENV || 'development'}}. Benefits: (1) Single import: const config = require('./config'), (2) Type conversion (string to number), (3) Default values, (4) Validation in one place, (5) Easy to test (mock config object). Usage: app.listen(config.server.port) instead of process.env.PORT. Better than accessing process.env.* throughout codebase (scattered, no defaults, no types).