Last time, in Setting Up Docker for Local Development, we got Postgres and Redis running the same way on every machine on the team. That solved "works on my machine" for the infrastructure. It didn't solve the other half of the problem: every one of those services needs credentials, and those credentials need to be different in local dev, staging, and production without anyone copy-pasting a database password into a Slack message.

This is part of the Full Stack SaaS Masterclass, the series where we're building a multi-tenant SaaS from an empty repo to something production-ready. Environment variables feel like the most boring topic in the whole series, and that's exactly why teams get them wrong. Nobody schedules time to think about config until a secret leaks into a git history or a staging database gets pointed at by a production deploy.

You don't need a giant secrets-management platform on day one. A handful of habits, applied consistently, scale fine from a solo project to a team of engineers, and they keep you from being one careless git add . away from a real incident.

Why config deserves its own discipline

Every real app has values that change between environments: database URLs, API keys, JWT secrets, third-party credentials, feature flags. The twelve-factor app methodology calls this out directly: config should live in the environment, not in the code, because code is the same across every deploy and config is not. If your DATABASE_URL is hardcoded, you can't run the same build against staging and production without editing source files, which defeats the entire point of having a build artifact.