Skip to main content
๐Ÿ“œ WAYPOINT LESSON

Environment-Specific Config and Secrets

โญโญ intermediateโณ 15 min read๐Ÿ“ Lesson 124 of 265

Dev/staging/prod differences, layered lookup, and the never-commit-a-secret discipline.

Environments differ by wiring, not by code

The same binary runs in dev (local DB, verbose logging), staging (prod shape, test data), production (real DB, sampled logging). The ENVIRONMENT NAME selects which config layer loads โ€” code never branches on if (env == "prod") for business behavior.

Layered lookup

string? Get(string key) =>
    Environment.GetEnvironmentVariable(Prefix + key)      // 1. env
    ?? FromJson(key)                                      // 2. appsettings.json
    ?? Defaults(key);                                     // 3. code defaults

Order matters and stays the same everywhere; production overrides staging overrides dev only through SOURCES, never through code paths.

Secrets: the discipline

API keys, connection passwords, signing keys:

  1. NEVER in source or Git history โ€” "we'll rotate before merging" is how breaches happen. Assume anything committed is burned forever.
  2. Secrets come from the environment or a secret store (env vars for this course; user-secrets tooling / vaults in real deployments).
  3. NEVER log them โ€” a request log that echoes an Authorization header is a leak. Log key NAMES, never values.
  4. No hardcoded fallbacks: config["ApiKey"] ?? "sk-dev-123" silently ships a credential.

Check your understanding

  • Where does "which DB is the staging one" live? (Staging's config source โ€” not an if in code.)
  • Why is a hardcoded default for a secret worse than throwing? (It silently ships a real credential; failing fast surfaces the misconfiguration.)

โšก Now practice

Ready to Code
Config Practice: Providers, Binding, SecretsBuild an environment provider, bind JSON into typed options, and close the hardcoded-secret hole.
3 challenges ยท ยท ~30 min