Debug the runtime
Compare effective configuration
Print safe configuration names and sources, then compare working and failing environments without exposing values.
10 minute lesson
The code is identical, but it works locally and fails deployed. Most of the time the difference is configuration: a missing variable, wrong scope, stale deployment, or unexpected default. The trap is debugging the config files. What matters is the effective configuration — what the process actually received at startup.
A variable can be set in .env, overridden by the shell, replaced by the deploy platform, or absent because nobody added it to production. Inspect what the process received, not what the files say it should receive.
Log a redacted startup summary
Log a redacted startup summary:
console.log({
nodeEnv: process.env.NODE_ENV,
apiHostConfigured: Boolean(process.env.API_HOST),
databaseUrlConfigured: Boolean(process.env.DATABASE_URL),
})
The Boolean() wrapping is deliberate. It answers “is it set?” without printing the value — DATABASE_URL contains a password, and this line will land in log storage. Never print secret values. Presence, source, version, and a safe fingerprint are usually enough.
Diff the environments
Run the same summary everywhere and put the outputs side by side:
local: { nodeEnv: 'development', apiHostConfigured: true, databaseUrlConfigured: true }
prod: { nodeEnv: 'production', apiHostConfigured: false, databaseUrlConfigured: true }
apiHostConfigured: false in production ends the investigation. The app fell back to a default host, and the default points somewhere wrong. Compare local, test, and deployed startup evidence this way for any config-shaped bug — the diff is the diagnosis.
The restart trap
Verify the process was restarted after changing environment configuration. Environment variables are read at process start. Editing the platform’s settings screen changes nothing for the process already running. This produces the most common false conclusion in config debugging: “I set the variable and it still fails” — because the failing process has never seen it.
When a value must be compared but not shown, log a fingerprint instead: the first 8 characters of its SHA-256 hash. Two environments with different fingerprints hold different values, and nobody learned the secret.
Lesson completed