Stop 16 · Security Across the StackTopics · 5/7

Secrets Management

Part of the Full Stack Developer Roadmap

In short

Bots scan public GitHub for leaked keys all day. Push your database password once, and someone may find it before you even notice. Secrets belong outside your code.

Keeping API keys, database credentials, and third-party secrets out of your codebase entirely — with special care that frontend-bundled env vars never accidentally include backend secrets.

The blob moves a key from a cupboard door into a small separate safe with a dial.

Think of it like this

Don't tape the key to the cupboard

Hanging the cupboard key on the cupboard door is convenient and also pointless. You keep the key somewhere else and bring it only when needed. Your code is the cupboard. Environment variables are how the key is handed over at run time.

Watch it happen

How a secret reaches your running app

Secret store
Env vars
process.env
Validate
App

1/5In production, DATABASE_URL lives in your host's secret settings. Locally it sits in a .env file that git ignores.

The big ideas

What you need to know

.env stays local

Add .env to .gitignore before your first commit. Commit a .env.example with key names and fake values instead.

Leaked means rotate

Deleting a pushed key from git isn't enough; it's in the history. Revoke it and create a new one immediately.

Frontend envs are public

Anything prefixed VITE_ or NEXT_PUBLIC_ ends up in the browser bundle. Never put a secret there.

Fail fast on boot

Validate env vars at startup so a typo crashes during deploy, not at 2 a.m. on the first payment.

See it in code

Walk through the code

ts
1// Node 20.6+ can load a .env file itself: node --env-file=.env server.js2import { z } from "zod";3 4const Env = z.object({5  DATABASE_URL: z.url(),6  JWT_SECRET: z.string().min(32),7  PORT: z.coerce.number().default(3000),8});9 10export const env = Env.parse(process.env); // crashes on boot if anything is missing

1/3Recent Node versions read .env files with a flag, so you may not need the dotenv package at all.

Import env from this file everywhere. One place to read secrets means one place to check, and TypeScript knows env.PORT is a number.

Save yourself the pain

Common mistakes

Oops

Committing .env once 'just for the team' and deleting it in the next commit.

Do this instead

It's still in git history. Rotate every key in it and share secrets through your host or a password manager.

Oops

Logging the whole config object on startup to debug.

Do this instead

Log which keys are present, never their values. Logs get shipped to many places.

Your mission

Audit one repo for secrets

~20 min

Quick check

You accidentally pushed a Stripe secret key to a public repo and removed it in the next commit. What should you do?

Go deeper

  1. 1Audit both your frontend and backend for any hardcoded secrets.
  2. 2Confirm no backend-only secret is prefixed in a way that gets bundled into your frontend's public JS.
  3. 3Use your hosting platforms' environment variable dashboards for all production secrets.

More topics at this stop

Stuck on this topic? Ask an Insider

Get 1:1 guidance from people who've walked this exact path — on the InsideEdge app.

Download
InsideEdge