Node.js › Environment Variables & Configuration

How would you structure application configuration to support multiple environments (development, staging, production) cleanly?

Intermediate

Answer

A common pattern centralizes all configuration access through a single config module that reads from process.env once at startup, provides sensible defaults for non-sensitive values, and exports a single typed configuration object used throughout the application -- this avoids scattering direct process.env.X references throughout the codebase (which makes it hard to see what configuration the application actually depends on, and hard to validate consistently).
// config.js -- single source of truth for configuration
module.exports = {
  port: parseInt(process.env.PORT, 10) || 3000,
  nodeEnv: process.env.NODE_ENV || 'development',
  databaseUrl: process.env.DATABASE_URL,
  isProduction: process.env.NODE_ENV === 'production',
};

// Elsewhere in the app
const config = require('./config');
app.listen(config.port);
Real-world example A codebase that previously had process.env.DATABASE_URL scattered across a dozen different files is refactored to route all configuration access through a single config.js module, making it immediately obvious from one file exactly what environment variables the entire application depends on.

Common follow-ups: How does this centralized config pattern make it easier to write a startup validation check covering every required variable?;What's the tradeoff of computing derived config values (like isProduction) once at startup versus checking process.env.NODE_ENV directly wherever needed?