Skip to content

Where Am I Supposed to Put My API Keys in Production?

6 min read

If you shouldn't hardcode your API keys, where do they actually go when the app is live? Your keys go into environment variables that you set in your hosting dashboard (Vercel, Netlify, Railway, and so on), not in your code. Your app reads them at runtime from the server's environment, so the secret value never sits in a file you commit and never ships to the browser.

Why this is confusing

When you were building on your laptop, your agent probably put your keys in a .env file, or worse, pasted them straight into the code so the demo would run. That worked, because on your machine everything is local and private. Then you deploy, the app can't find the keys, and something breaks with a vague error.

The agent built the thing you asked for: a working demo. It did not set up the part you didn't ask about, which is where the real keys live once other people are using the app. A .env file is meant to stay on your machine. In production, the hosting platform holds the secrets instead, and your code just asks for them by name.

How to check where yours are now

  1. Search your code for the actual secret values. In your project folder, look for strings like sk_live, sk-, AIza, or a long random-looking token sitting in a .js, .ts, .py, or config file. Any hardcoded key is a problem.
  2. Open .gitignore and confirm it lists .env. Then run git log -- .env. If that prints commits, your .env was committed at some point and the keys in it should be treated as leaked.
  3. Check your hosting dashboard. In Vercel, Netlify, or Railway, find the Environment Variables (or Secrets) section for your project. If it's empty but your app uses keys, they are almost certainly hardcoded somewhere they shouldn't be.

The fix

  1. Move every key into an environment variable. In your code, replace the pasted value with a lookup: process.env.STRIPE_SECRET_KEY in Node, or os.environ["STRIPE_SECRET_KEY"] in Python. The code now names the key instead of containing it.
  2. Set those variables in your hosting dashboard, not in a committed file. On Vercel: Project → Settings → Environment Variables. On Netlify: Site settings → Environment variables. On Railway: your service → Variables. Paste the real value there and save.
  3. Keep secret keys server-side. A key with a NEXT_PUBLIC_ prefix (or any "public"/"publishable" key) is bundled into the browser on purpose. A secret key must never carry that prefix and must only be read in server code, never in a component that renders in the browser.
  4. Add .env to .gitignore and keep a .env.example with the variable names only, no values, so future you knows which keys the app needs.
  5. Redeploy and test. Trigger the feature that uses each key (a test payment, an AI call) and confirm it works against the dashboard values.

The trap to avoid

Do not "fix" a leaked key by deleting it from the code and moving on. Once a secret has been committed to git or shipped to the browser, it is public forever, even after you remove it. You have to rotate it: generate a new key in the provider's dashboard (Stripe, OpenAI, and so on), revoke the old one, and put only the new value into your hosting environment. Moving a compromised key around does not make it safe again.

Where this fits

Missing or misplaced keys are one of the most common reasons a vibe-coded app works in the demo and then breaks the moment it's live, and a leaked secret is the kind of thing you want to catch before strangers do. The free Readiness Report checks your real project for hardcoded and exposed keys and tells you which ones need rotating. If you'd rather have the fixes handed to you in order, that's what the Finishing Pass is for. For the mechanics behind all of this, see what are environment variables, and if a key has already gone public, start with I accidentally pushed my API keys to GitHub.