- environments
- environment variables
- secrets
- .env
- 12-factor
- .gitignore
Environments & Secrets — Config Without Catastrophe 🔐
A true story (it happens constantly). A developer accidentally committed their AWS key to a public GitHub repo. Bots scrape GitHub for keys every minute — within 9 minutes theirs was found and used to spin up servers mining crypto. The bill: tens of thousands of dollars. This lesson is how you never become that story.
🧠 The mental model: rehearsal → dress rehearsal → opening night
Your code runs in several environments — same script, very different stakes:
| Environment | Like... | Talks to |
|---|---|---|
| development | rehearsing in your bedroom | fake / local data |
| staging | dress rehearsal on the real stage | a copy of production |
| production | opening night, live audience | the real database & users |
The golden rule: the exact same build runs everywhere. Only the configuration changes.
Config lives in the environment, not the code (the "12-Factor" rule)
How does the same build know which database to use? Environment variables — values set outside your code, per environment:
Pythonimport os DATABASE_URL = os.environ["DATABASE_URL"] # set per-environment, never hardcoded ENV = os.environ.get("ENV", "development") # .get() with a safe default
Locally you keep them in a .env file; in production your platform (Vercel, AWS…) injects them.
The secret rules (memorise these)
- ›Never put keys, passwords, or tokens in source code or Git.
- ›Add
.envto.gitignoreso it is never committed.- ›If a secret leaks, rotate it immediately — deleting the commit is NOT enough, because Git keeps history.
bash# .gitignore .env *.key
The #1 production outage you'll cause
A required secret that is present but empty (""). The app boots, then explodes three hours into the night run. Validate config at startup and fail loudly — an empty string is "missing".
🔧 Try it for real
bashecho 'API_KEY=test123' > .env # create local config echo '.env' >> .gitignore # make sure it's never committed python -c "import os; print(os.environ.get('API_KEY', 'NOT SET'))"
Your Task
Read a config dict, detect the environment, and validate that all required secrets are present — treating an empty value as missing (the classic outage).