foundation

Configuration

Load configuration deterministically, validate it at startup, separate config from secrets, and expose safe defaults.

Configuration is data that changes between environments but not between deploy artifacts — load it once at startup, validate shape, and inject into modules instead of reading env vars everywhere.

					import { z } from 'zod';

const ConfigSchema = z.object({
  port: z.coerce.number().default(3000),
  databaseUrl: z.string().url(),
  logLevel: z.enum(['debug', 'info', 'warn']).default('info'),
});

export const config = ConfigSchema.parse({
  port: process.env.PORT,
  databaseUrl: process.env.DATABASE_URL,
  logLevel: process.env.LOG_LEVEL,
});
				

Fail fast: invalid config should prevent listening on a port. Separate secrets from non-secret config — secrets rotate on different cadence and need stricter access.

12-factor style: store config in environment, but centralize parsing in one module. Avoid `process.env.FEATURE_X` scattered in business logic.

On interviews: startup validation; feature flags vs config; how to test with alternate config without mutating global env.

Common pitfalls: silent defaults hiding misconfiguration; different config paths in dev vs prod; baking secrets into config files in the image.

The trade-off is balancing simplicity, performance, safety, and operability — name which axis you optimized and what cost you accepted.

Checklist:

  • Single config module exported as readonly object.
  • Schema validation at boot.
  • Document required variables.
  • Immutable after initialization.