Every project has secrets — API keys, database passwords, JWT signing keys, third-party tokens. Handling them badly is one of the most common and most damaging mistakes in software. Here's how I actually manage it.
Never commit secrets to Git
The single most important rule. Secrets in a Git repo — even a private one — are a liability forever, because Git history keeps everything. Deleting the file later doesn't remove it from history. Once it's committed, treat that secret as compromised and rotate it.
.env files, kept out of version control
Secrets live in a .env file, loaded at runtime, and that file is always in .gitignore. I commit a .env.example with the variable names but no real values, so anyone setting up the project knows what's needed without ever seeing the actual secrets.
# .env.example DATABASE_URL= JWT_SECRET= GROQ_API_KEY=
Different secrets for different environments
Development, staging, and production never share credentials. If a dev database password leaks it's an inconvenience. If it's the same password as production, it's a disaster. Separate secrets per environment contains the damage of any single leak.
Rotating regularly and after any suspicion
API keys and secrets should be rotated periodically, not left in place indefinitely. And immediately if there's any suspicion of exposure — a leaked log, a screen share that went wrong, anything. Most services make rotation easy; use that.
Least privilege
An API key should only have the permissions it actually needs. A key used for read-only operations shouldn't have write access just because it was convenient to set up that way. Scoping keys tightly limits the damage if one does leak.
Secrets in Docker
For Docker Compose, secrets come through environment variables referencing the .env file, never hardcoded in the Compose file itself, never baked into an image. An image with a secret baked in means anyone who gets the image gets the secret — a much bigger surface than you'd want.
What I do when I've genuinely leaked one
Rotate immediately, check logs and access records for any unauthorised use in the window it was exposed, and treat it as fully compromised regardless of how confident I am nobody actually used it. Assuming the worst and rotating is always cheaper than assuming the best and being wrong.