Back to resources
// technical · security

Handling secrets properly

One secret committed by mistake, and it's your database or Stripe key on GitHub forever. Here's where secrets should live, how to inject them per environment, and what to do when one leaks.

TechnicalJul 24, 2026~7 min · intermediate
.envSecrets ManagerCI variablesrotationgit
01

The golden rule

A secret never lives in the code, nor in the git repo. It lives in the environment, injected at runtime. The code reads process.env; it never knows the value.

.gitignorecopy
# .gitignore — la premiere ligne de defense
.env
.env.local
.env*.local
# et si un secret a DEJA ete commite : le retirer de l'historique
# (git rm --cached + git filter-repo) ET le faire tourner immediatement
!

A .env committed once stays in git history forever, even if deleted later. The only real fix: rotate (revoke + regenerate) the exposed secret.

02

Where they live, per environment

local.env.local, gitignored, never shared via git
CImasked variables in GitLab/GitHub, not in the YAML
prod (managé)env variables of Vercel / Amplify
prod (AWS)Secrets Manager or SSM Parameter Store
i

Masked CI/CD variables are exactly those from using GitLab CI/CD well.

03

Reading them properly

Two reflexes: never put a secret in a NEXT_PUBLIC_ variable (it ends up in the client bundle), and validate that secrets are present at boot rather than discovering one is missing mid-request in prod.

config.tscopy
// on lit les secrets via process.env, jamais en dur dans le code
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY);
// valider leur presence au boot : mieux vaut crasher au demarrage
// qu'a la premiere requete en prod
["STRIPE_SECRET_KEY", "DATABASE_URL"].forEach((k) => {
if (!process.env[k]) throw new Error(`Missing env var: ${k}`);
});
i

The NEXT_PUBLIC_ boundary is the same trap as in the basic security holes in a Next.js app.

04

Rotation & leaks

rotate secrets regularly, and immediately at the first doubt;
one secret per environment: the staging key isn’t the prod one;
a secret scan in CI (gitleaks) to catch a leak before merge;
on a leak: revoke first, investigate after. The order matters.
05

Sources & further reading

01OWASP — Secrets Management Cheat SheetThe general framework: centralized storage, lifecycle, automated rotation, incident response.02Next.js — How to use environment variablesThe .env load order and why a NEXT_PUBLIC_ variable gets inlined into the client bundle at build time.03GitHub Docs — Removing sensitive data from a repositoryThe official procedure: revoke/rotate the secret first, rewrite history with git filter-repo after.04gitleaks — Secret detection for git reposThe tool to wire into CI or a pre-commit hook to catch a key before the merge.05AWS — Rotate AWS Secrets Manager secretsScheduled automatic rotation, with native integrations for databases.06AWS — Systems Manager Parameter StoreKMS-encrypted SecureString, parameter hierarchies, IAM — the cheaper alternative when rotation isn't required.07Vercel — Sensitive environment variablesVariables that can't be read back after creation, build-log redaction, team-wide policy.

Handling secrets is a simple discipline: out of the code, out of git, injected by the environment, validated at boot, and rotated without hesitation. A CI scan as a net, and your database key will never end up in a public repo.