Books/Deploying AI Apps/Environment Variables and Secrets

    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:

    1. They cost real money — Someone could make thousands of API calls on your account
    2. Usage is hard to reverse — Once tokens are consumed, you pay for them
    3. Rate limits apply to you — Abusers could exhaust your rate limits, breaking your app for real users
    4. 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:

    FrameworkPrefix for Client-Side VariablesConfig File
    Next.jsNEXT_PUBLIC_.env.local
    ViteVITE_.env
    Create React AppREACT_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:

    1. Immediately rotate the key (generate a new one in the API provider's dashboard)
    2. Remove it from Git history (this is complex — ask your AI for help)
    3. 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:

    ProviderWhere to Set Limits
    OpenAISettings → Billing → Usage limits
    AnthropicSettings → Plans & Billing → Spending limit
    Google AIGoogle 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]."


    🌐 www.genai-mentor.ai