Out of Code, Out of Git, In Memory Only
Managing Secrets
Secrets — DB URLs, API keys, JWT secrets — never go in git. Use env vars, secret managers, and rotation.
What you'll learn
- Use env vars correctly
- Pick a secret manager
- Rotate compromised secrets immediately
The single most common production incident: someone committed a secret to git. Don’t be that someone.
Rules
- Never commit
.envfiles - Always add
.env*to.gitignore - Always check git history before pushing
- Rotate immediately if a secret leaked — even once
.gitignore
# .gitignore
.env
.env.*
!.env.example The !.env.example pattern keeps an example committed (template
of expected vars).
A .env.example
# .env.example
PORT=3000
NODE_ENV=development
DATABASE_URL=
JWT_SECRET=
SESSION_SECRET=
GOOGLE_CLIENT_ID=
GOOGLE_CLIENT_SECRET= Empty values. Devs copy this to .env and fill in.
Load With Node 22+
node --env-file=.env src/index.js Or via dotenv:
import "dotenv/config";
console.log(process.env.JWT_SECRET); Validate at Boot
Crash fast at startup beats crashing mid-request:
// src/config/env.js
import { z } from "zod";
const Schema = z.object({
PORT: z.coerce.number().int().default(3000),
NODE_ENV: z.enum(["development", "test", "production"]).default("development"),
DATABASE_URL: z.string().url(),
JWT_SECRET: z.string().min(32),
SESSION_SECRET: z.string().min(32),
});
export const env = Schema.parse(process.env); If a required var is missing, the app refuses to start.
Real Production
Env files are fine for dev. For production:
| Platform | Secret store |
|---|---|
| Heroku / Render / Fly | Built-in env-var UI |
| AWS | Secrets Manager or Parameter Store |
| GCP | Secret Manager |
| Azure | Key Vault |
| Self-hosted | HashiCorp Vault, Doppler, Infisical |
| Kubernetes | Sealed Secrets, External Secrets Operator |
Pull at startup, never bake into images.
When A Secret Leaks
It’s not “if” — it’s “when.” Have a plan:
- Rotate immediately — invalidate the old secret
- Audit usage — was the old secret actually used?
- Force re-issue for downstream consumers
- Document the incident
For DB credentials, JWT secrets, and OAuth client secrets — rotation is straightforward. Plan for it. Practice once before you need it.
Never Log Secrets
The fastest way to leak a secret is a stack trace in your logs:
console.log(`connecting with ${process.env.DATABASE_URL}`); // 🚨 Even structured logs ship to log services. Mask sensitive values. Most secret managers warn on leaked values; configure them.
End of Chapter
Auth and security done. Next chapter: data — databases, ORMs, uploads, streaming, queues.
Database Integration →