← Back to articles

Configuration

· 2 min read · backend · ... views
Share: Y
On this page

Hardcoding database URLs, API keys, and feature flags in your source code is a disaster waiting to happen. Different environments (dev, staging, prod) need different configs. Secrets should never appear in git. And you need to change config without redeploying.

The 12-Factor App Rule

One of the most important principles: store config in environment variables. Your code should read configuration from the environment, not from hardcoded values.

// Bad
const DB_URL = "postgres://admin:password123@prod-db.example.com/myapp"

// Good
const DB_URL = process.env.DATABASE_URL

This way the same code runs everywhere, dev, staging, prod, with different env vars.

What Counts as Config?

Config Types

  • Database connection strings
  • API keys and secrets
  • Port numbers
  • Feature flags
  • External service URLs
  • Cache TTLs
  • Rate limit thresholds
  • Log levels

If it changes between environments, it’s config.

Secrets Management

Secrets Flow

Never put secrets in:

  • Source code
  • Git history
  • Docker images
  • Log files

Instead use:

  • Environment variables (basic, works everywhere)
  • Secret managers (AWS Secrets Manager, HashiCorp Vault, Doppler)
  • Encrypted config files (decrypted at runtime)

Secret managers are best because they:

  • Rotate secrets automatically
  • Audit who accessed what
  • Inject secrets at deploy time without human involvement

Config Hierarchy

Most apps layer config from multiple sources:

defaults < config file < environment variables < CLI flags

Each layer overrides the previous. So a default port of 3000 can be overridden by a config file, which can be overridden by an env var.

Validation at Startup

Don’t wait until the first database query to discover your DB_URL is missing. Validate ALL required config at startup:

App starts
  1. Load config from env vars
  2. Validate: DB_URL? Present. API_KEY? Present. PORT? Valid number.
  3. Missing something? CRASH immediately with a clear error.
  4. All good? Continue booting.

Fail fast. A clear “missing DATABASE_URL” error at startup is infinitely better than a cryptic error 2 hours later when someone hits the database endpoint.

Wrapping Up

  • Never hardcode config or secrets
  • Use environment variables as the primary mechanism
  • Validate all config at app startup
  • Use secret managers for production
  • Layer config: defaults < file < env < flags (each overrides previous)
  • Different environments = different config, same code

Day 15 of 95 | Backend Engineering Series

Enjoyed this article?
Share: Y

Get new articles in your inbox

No spam. Unsubscribe anytime.

Get in touch

Have a question, feedback, or just want to say hi? Reach out.