A secret is any credential your code needs but no one else should have: database passwords, API keys , signing keys, tokens. The whole problem is keeping the secret out of every place that gets shared, and a surprising number of places get shared.
The rule is one sentence: a secret never goes in your source code. Everything below is a consequence of that rule.
Where Secrets Leak
The mistake is almost always the same: a value typed directly into a file that later travels somewhere you didn't think about:
- Committed to git. Even if you delete it in the next commit, it's still in the history. Anyone who clones the repo gets every version of every file. A leaked key isn't un-leaked by a later commit. It has to be rotated (revoked and reissued).
- Baked into a built artifact. A secret in a Docker image or a frontend bundle ships with every copy of that artifact to everyone who can pull it.
- Printed to logs. Logging a whole request object, or a config dump on startup, quietly writes the secret into log files and log aggregators that a much wider group can read.
How to Use It
Keep secrets in the environment, not the code. The app reads them at runtime; the file that holds them is never committed.
# .env, listed in .gitignore, never committed
DATABASE_URL=postgres://app:s3cr3t@db:5432/app
STRIPE_API_KEY=sk_live_... // The code references the name, never the value
const stripe = new Stripe(process.env.STRIPE_API_KEY); # .gitignore: the single most important line in this section
.env
For a solo project or one machine, a .env file kept out of git is enough. Once a
team shares infrastructure, move up to a secret manager : AWS Secrets Manager,
HashiCorp Vault, Google Secret Manager. These store the value encrypted, hand it to the app at
runtime, control who can read each secret, and give you an audit log and one-click
rotation. The code still just reads a name; only the source of the value changes.
Heads-up: if a secret ever lands in a commit, rotating it is not optional. Force-pushing to erase the commit is not sufficient. Assume every clone, fork, and CI cache already has it. Revoke the old credential and issue a new one.
Common Reason You May Need This
- Connecting to a database, payment processor, or any third-party API
- Signing tokens or sessions (the signing key is a secret; see Password Hashing and the IAM guide)
- Sharing a codebase publicly, or even privately across a team, without leaking access along with it
Check your understanding
You deleted a committed key an hour later: are you safe?
You committed an API key, noticed an hour later, and deleted it in a new commit. Are you safe?