Environment Variables and Secrets
Environment Variables and Secrets
Your AI app probably calls APIs like OpenAI, Anthropic, or Google AI. Each of these requires an API key — a secret string that authenticates your app. If someone gets your API key, they can use your account and run up your bill. Environment variables are how you keep these keys safe.
Why Environment Variables Matter
An environment variable is a key-value pair that exists outside your code. Instead of writing your API key directly in your code (hardcoding), you reference it through a variable that gets its value from the environment.
The wrong way (hardcoded):
// ❌ NEVER DO THIS — anyone who sees your code sees your key const openai = new OpenAI({ apiKey: "sk-abc123xyz789...", });
The right way (environment variable):
// ✅ The key comes from the environment, not the code const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY, });
Why This Matters for AI Apps
AI API keys are especially dangerous to leak because:
- They cost real money — Someone could make thousands of API calls on your account
- Usage is hard to reverse — Once tokens are consumed, you pay for them
- Rate limits apply to you — Abusers could exhaust your rate limits, breaking your app for real users
- Some keys grant broad access — An admin key might allow model fine-tuning, data deletion, or account changes
.env Files
The standard way to manage environment variables locally is with a .env file in your project root:
# .env OPENAI_API_KEY=sk-abc123xyz789... ANTHROPIC_API_KEY=sk-ant-abc123... DATABASE_URL=postgresql://user:pass@host:5432/db NEXT_PUBLIC_APP_URL=http://localhost:3000
Your app reads these variables using process.env:
const apiKey = process.env.OPENAI_API_KEY; const dbUrl = process.env.DATABASE_URL;
Framework-Specific Prefixes
Different frameworks handle environment variables differently:
| Framework | Prefix for Client-Side Variables | Config File |
|---|---|---|
| Next.js | NEXT_PUBLIC_ | .env.local |
| Vite | VITE_ | .env |
| Create React App | REACT_APP_ | .env |
| Node.js (backend) | No prefix needed | .env |
Important: Variables with the public prefix are exposed to the browser. Never put secret API keys in client-side environment variables!
# ✅ Safe — only accessible on the server OPENAI_API_KEY=sk-abc123... # ⚠️ Exposed to the browser — don't put secrets here NEXT_PUBLIC_APP_NAME=My AI App VITE_APP_TITLE=My AI App
What to ask your AI: "Which of my environment variables should be public vs. private? Here's my .env file: [paste variables without values]."
The .env.example File
Always create a .env.example file that shows what variables are needed — but without the actual values:
# .env.example — commit this to Git OPENAI_API_KEY=your-openai-api-key-here ANTHROPIC_API_KEY=your-anthropic-api-key-here DATABASE_URL=your-database-url-here NEXT_PUBLIC_APP_URL=http://localhost:3000
This file serves as documentation. When a new developer (or your future self) clones the project, they know exactly which variables to set up.
# New developer setup: cp .env.example .env # Then fill in the real values
Environment Variables on Different Platforms
When you deploy, you can't just upload a .env file. Each platform has its own way to set environment variables.
Vercel
# Via CLI vercel env add OPENAI_API_KEY # Or in the Vercel dashboard: # Project Settings → Environment Variables → Add
Vercel lets you set different values per environment (Production, Preview, Development).
Firebase
For Firebase Cloud Functions:
# Set a secret firebase functions:secrets:set OPENAI_API_KEY # You'll be prompted to enter the value # Reference in your function import { defineSecret } from "firebase-functions/params"; const openaiKey = defineSecret("OPENAI_API_KEY"); export const chat = onRequest( { secrets: [openaiKey] }, (req, res) => { const key = openaiKey.value(); // Use the key... } );
For Firebase Hosting (client-side), use the Firebase config object or .env files with your framework's prefix.
Netlify
# Via CLI netlify env:set OPENAI_API_KEY "sk-abc123..." # Or in the Netlify dashboard: # Site Settings → Environment Variables → Add
Railway
# Via CLI railway variables set OPENAI_API_KEY=sk-abc123... # Or in the Railway dashboard: # Project → Variables → New Variable
What to ask your AI: "I'm deploying to [platform]. How do I set up my environment variables for [list your variables]?"
Secret Management Best Practices
1. Never Commit Secrets to Git
This is the number one rule. Add .env to your .gitignore:
# .gitignore .env .env.local .env.*.local
If you accidentally commit a secret:
- Immediately rotate the key (generate a new one in the API provider's dashboard)
- Remove it from Git history (this is complex — ask your AI for help)
- The old key should be considered compromised forever
2. Use Different Keys Per Environment
# .env (development) OPENAI_API_KEY=sk-dev-key-with-low-limits... # Production (set in hosting platform) OPENAI_API_KEY=sk-prod-key-with-higher-limits...
This way, development mistakes don't affect your production quota.
3. Set Spending Limits
Most AI API providers let you set monthly spending caps:
| Provider | Where to Set Limits |
|---|---|
| OpenAI | Settings → Billing → Usage limits |
| Anthropic | Settings → Plans & Billing → Spending limit |
| Google AI | Google Cloud Console → Budgets & alerts |
4. Use the Principle of Least Privilege
Only give each key the permissions it needs:
- Development keys: Low rate limits, restricted models
- Production keys: Higher limits, only the models your app uses
- Never use admin/owner keys in your application code
5. Rotate Keys Regularly
Change your API keys periodically (every 90 days is a good practice). Update them in your hosting platform, and the old keys stop working.
6. Validate Variables at Startup
Check that all required environment variables are set when your app starts:
// src/lib/env.ts function requireEnv(name: string): string { const value = process.env[name]; if (!value) { throw new Error( `Missing required environment variable: ${name}. Check your .env file.` ); } return value; } export const env = { OPENAI_API_KEY: requireEnv("OPENAI_API_KEY"), DATABASE_URL: requireEnv("DATABASE_URL"), APP_URL: process.env.NEXT_PUBLIC_APP_URL || "http://localhost:3000", };
This gives you a clear error message instead of a confusing undefined error later.
What to ask your AI: "Create an environment variable validation file for my app. Here are the variables I need: [list them]. Some are required, some are optional."
Environment Variable Checklist for AI Apps
✅ AI API keys are in server-side env vars (no NEXT_PUBLIC_ prefix)
✅ .env is in .gitignore
✅ .env.example exists with placeholder values
✅ Production env vars are set in your hosting platform
✅ Spending limits are set on AI API accounts
✅ Different API keys for development and production
✅ Variables are validated at app startup
✅ No secrets are hardcoded in any source file
What's Next?
Your secrets are safe. Now let's actually deploy your app! The next tutorial walks you through deploying to Vercel and Firebase step by step.
What to ask your AI: "Audit my project for any hardcoded secrets or exposed API keys. Here's my project structure: [describe or paste file list]."