On this page
  1. The principle
  2. Step 1 — Separate config from code
  3. Step 2 — Use .env for local dev only
  4. Step 3 — Use a secret manager in production
  5. Step 4 — Reference, don’t copy
  6. Step 5 — Rotate on exposure
  7. Where AI coding assistants get this wrong
  8. Checklist
  9. FAQ
    1. Are environment variables secure?
    2. What is the difference between config and secrets?
    3. Should I commit a .env.example?
  10. Related topics
  11. Sources
tutorial

How to Manage Secrets and Environment Variables Properly

Store secrets outside your code: environment variables for config, a secret manager for sensitive values, and never commit .env files. A practical guide.

Quick answer

  • Keep secrets out of code: read them from the environment at runtime, never hardcode them.
  • Use a .env file for local development only — and make sure it’s gitignored.
  • Use a real secret manager (cloud, vault) for production values, and rotate on exposure.

The principle

Configuration and secrets belong in the environment, not the code, because code gets committed, copied, and shared. This is Factor III of the Twelve-Factor App: config varies across deployments, so it must be strictly separated from the code that’s identical everywhere. Secrets take that further — they must be separated and protected.

Step 1 — Separate config from code

Read values from the environment:

import os
DATABASE_URL = os.environ["DATABASE_URL"]

Never DATABASE_URL = "postgres://..." in the source. How to verify it worked: the code contains no secret values, only the variable names.

Step 2 — Use .env for local dev only

Create a .env file:

DATABASE_URL=postgres://localhost:5432/app
API_KEY=your-local-key

Load it with a library like python-dotenv or dotenv. Then add it to .gitignore:

.env
.env.*

How to verify it worked: git status never shows .env, and git ls-files confirms it’s untracked.

Step 3 — Use a secret manager in production

Cloud platforms and dedicated tools (AWS Secrets Manager, Vault, your host’s secret store) hold production secrets and inject them at deploy time. The app reads the environment the platform provides — no .env file is committed or copied to the server.

Step 4 — Reference, don’t copy

Pass secrets into the environment without ever pasting them into code, config committed to the repo, or CI logs. In CI, use the platform’s encrypted secret store and reference it:

env:
  API_KEY: ${{ secrets.API_KEY }}

Step 5 — Rotate on exposure

If a secret is ever committed or leaked, treat it as compromised: rotate it, then remove it from history. See How to Automate API Key Rotation.

Where this bites vibecoders

The AI assistant, given a key, will place it directly in the code or a config file because it has no convention to follow unless you give it one. The convention to enforce: secrets are read from the environment, always. Add .env to .gitignore on day one, and treat any secret that ever appeared in the repo as already leaked.

Where AI coding assistants get this wrong

  • Hardcoding secrets in source or committing .env files.
  • Generating example configs with live-looking values that get copied verbatim.
  • Logging secrets in debug output.
  • Using the same secret in many places, so one leak exposes everything.

Checklist

  • Read all config and secrets from the environment.
  • Gitignore .env and any key files from the start.
  • Use a secret manager for production.
  • Reference secrets in CI, never print them.
  • Rotate immediately on any suspected exposure.

FAQ

Are environment variables secure?

They keep secrets out of code, which is the main goal, but they’re not encryption — anything that can read a process’s environment can read them. For high-value secrets, a secret manager with access control and rotation is the stronger choice. Env vars are the right interface; the manager is the right store.

What is the difference between config and secrets?

Config is non-sensitive, deploy-specific settings (a URL, a feature flag); secrets are credentials (keys, passwords, tokens). Both belong in the environment, but secrets additionally need encryption, access control, and rotation.

Should I commit a .env.example?

Yes — a .env.example with the names and dummy values documents what’s required without leaking real secrets. Just never commit the real .env. See Why Do .env Files Keep Leaking Secrets?.

Sources

Share: