Guides
Where Should I Put API Keys in an AI-Built App?
If you built your app with an AI coding tool, your API keys may already be in the wrong place — hardcoded in source files, committed to GitHub, or embedded in frontend JavaScript where any browser can read them. This guide explains exactly where keys should live at every stage: local development, staging, and production.
Updated July 2026 · 10 min read
Written for AI makers using tools like Cursor, Bolt, Lovable, Replit, Claude, and ChatGPT.
Quick answer
Store API keys in a .env file locally (never committed to Git) and in your hosting platform's environment variables panel in production. Never put secret keys in source code, GitHub, or frontend JavaScript that the browser downloads. Use backend routes to make API calls server-side.
Who this is for
- You found API keys in your project's source code and do not know if that is safe
- You are about to deploy and want to confirm keys are in the right place
- You are confused about
.envfiles, environment variables, and what goes where
What you'll need
- Your project folder open on your computer
- A
.envfile or at least knowledge of what API keys your app uses - Access to your hosting platform dashboard (Vercel, Railway, Render, etc.)
The one rule that covers everything
API keys are secrets. Secrets must only exist in places that are not readable by the public. That means: not in source files, not in Git history, not in the browser, and not in screenshots or Notion pages.
The two safe locations are: a local .env file on your development machine (excluded from Git), and your hosting platform's environment variables panel (injected at runtime, never stored in code).
Everything else in this guide flows from that rule. If a key ends up anywhere else, it is in the wrong place — regardless of whether your AI coding tool put it there.
Local development: the .env file
A .env file is a plain text file in your project root. Each line is a variable name and value: OPENAI_API_KEY=sk-proj-abc123. Your app reads it at startup. Locally, this file works as your private configuration store.
The .env file must be listed in .gitignore — a one-line addition (.env) that tells Git to skip this file forever. Verify this before your first commit. If you can see .env in GitHub Desktop's changed-files list, it is not yet ignored.
Create a companion file called .env.example that lists the same variable names with fake placeholder values (OPENAI_API_KEY=your_key_here). Commit .env.example to GitHub — it documents what variables the app needs without exposing real secrets. Anyone cloning the project copies .env.example to .env and fills in real values.
Production: your hosting platform's environment panel
When you deploy, your .env file stays on your laptop. The hosting platform has no access to it. You need to paste each variable name and its production value into the platform's environment variables interface.
On Vercel: Project → Settings → Environment Variables. On Railway: your service → Variables tab. On Render: Environment → Environment Variables. On Netlify: Site settings → Environment variables. Each platform injects these values at runtime, so your app can read them through process.env or os.environ — exactly as it reads them locally from .env.
Use production API keys in production and test or sandbox keys locally wherever providers offer them. Stripe, for example, provides test keys (sk_test_...) for local development. This limits damage if a development machine or .env file is ever compromised.
Why secrets cannot live in source code
When you hardcode a key in a .js, .ts, or .py file, it gets saved to Git history on the first commit. Even if you delete it later, the value remains readable in every commit that predates the deletion. Bots continuously scan GitHub for known key patterns.
Source code is also often shared. You send snippets to teammates, paste them into error reports, or use them in documentation. A real key embedded in code becomes a liability every time that code moves.
AI coding tools sometimes write keys directly into source files as part of generated integrations. Always review generated code for string literals that look like secrets (long random strings, anything starting with sk-, pk-, eyJ, or similar provider-specific prefixes).
Frontend vs backend: where your code runs matters
Frontend code — React components, Vue templates, plain JavaScript in the browser — runs on your users' machines. There is no way to hide a value in frontend code. Anyone can open browser DevTools, view the network panel, or read your bundled JavaScript source.
Secret API keys must only ever appear in backend code: Next.js API routes, a Node.js server, a Django view, a serverless function. The backend receives requests from your frontend, makes the authenticated API call with the secret key, and returns only the safe result.
Some providers offer keys designed for browser use: Stripe's publishable key for checkout, Supabase's anon key with row-level security. These have limited permissions. Even then, read the provider's documentation carefully before trusting a key in the browser. When in doubt, proxy through a backend route.
The NEXT_PUBLIC_ and VITE_ trap
Next.js and Vite expose environment variables to the browser only when they start with NEXT_PUBLIC_ or VITE_. This is intentional for non-sensitive values like your app's public URL or a publishable API key.
The trap: AI tools sometimes generate code like NEXT_PUBLIC_OPENAI_API_KEY=sk-proj-... because the frontend component that calls OpenAI needs to access the variable. This sends a secret key to every browser that loads your page.
The fix is to move the API call to a backend API route or server action. The frontend calls your own endpoint (like /api/chat), your backend reads process.env.OPENAI_API_KEY (without the NEXT_PUBLIC_ prefix), makes the OpenAI request, and returns the response. The secret never leaves the server.
GitHub safety and .gitignore
GitHub is public by default and even private repositories carry risk — collaborators, forks, accidental visibility changes. Never commit API keys under any circumstances.
Your .gitignore file should include .env on its own line. Many framework starter templates include this, but verify it is present. If your AI tool generated a project without .gitignore, create one before your first git add.
If you suspect a key was already committed, do not just delete the file and commit again — the value remains in Git history. The right response is to rotate the key immediately with the provider, then optionally clean up history. Rotation is the non-negotiable step; history cleanup is secondary.
How to check your current app right now
Search your project folder for strings that look like secret values: sk-, pk-, Bearer, api_key=, apiKey:, and any values you know are real keys. Most code editors have a project-wide search (Cmd+Shift+F or Ctrl+Shift+F). If any appear in source files rather than .env, move them.
Open .gitignore and confirm .env appears in it. Then open GitHub Desktop or run git status — if .env is listed as an untracked or changed file, it is not ignored and could be committed accidentally.
Check that your deployed app is reading the right values. Test a feature that requires an API key. If it works locally but fails in production, the hosting platform is missing that environment variable.
Step-by-step
- 1
Step 1
Find any hardcoded keys
Search your project for patterns like sk-, pk-, Bearer, api_key, and apiKey. Check .js, .ts, .py, .jsx, .tsx, and any config files. If you find real key values as string literals (not
process.env.VARIABLE_NAME), note them — they need to move. - 2
Step 2
Create or update your .env file
In your project root, create
.envif it does not exist. Add each key as KEY=value on its own line. Remove the hardcoded values from source files and replace them withprocess.env.KEY (Node/Next.js) or os.environ['KEY'] (Python/Django). - 3
Step 3
Add .env to .gitignore
Open or create
.gitignorein your project root. Add a line containing just.env. Save. Verify in GitHub Desktop or git status that.envno longer appears in the file list for staging. - 4
Step 4
Create .env.example
Copy your
.envfile to.env.example. Replace every real value with a placeholder string (OPENAI_API_KEY=your_openai_key_here). Commit.env.example— it is safe to share. Keep.envlocal-only. - 5
Step 5
Add variables to your hosting platform
Log into your hosting dashboard. Find the environment variables section for your service. Add each variable from your
.envfile using the production key values. Trigger a redeploy so the app picks up the new values.
Common mistakes
NEXT_PUBLIC_prefix on secret API keysHow to fix it: Remove the prefix and move the API call to a backend route. Secret keys must never be accessible in browser JavaScript.
Committing
.envto GitHub before checking.gitignoreHow to fix it: Add
.envto.gitignorebefore the very first git add. If it was already committed, rotate the keys immediately.Copying production keys into
.env.exampleHow to fix it:
.env.examplemust use placeholder strings only. Real values in.env.exampledefeat the purpose of the file.Forgetting to add variables to the hosting dashboard after setting them locally
How to fix it: The
.envfile does not travel to the server. Every key must be re-entered in the hosting platform's environment variables panel.Calling third-party AI APIs directly from React components
How to fix it: Create a Next.js API route or equivalent backend endpoint. The component calls your own endpoint; your backend calls the external API with the secret key.
Assuming a private GitHub repo is safe for secrets
How to fix it: Collaborators, forks, and repository settings changes all create exposure risk.
.gitignoreand environment variables are the correct solution regardless of repository visibility.
Copy-ready prompt
Prompt: fix API key placement in this project
Paste this into Cursor, Claude, ChatGPT, Bolt, Lovable, or your AI coding tool.
Ready to paste
Review this project for API key placement and fix any problems. Tasks: 1. Find all hardcoded API key values, tokens, and secret-like strings in source files. 2. Move every secret value to environment variables. Update .env with real values and replace source code references with process.env.VARIABLE_NAME (or equivalent for this stack). 3. Confirm .env is in .gitignore. Add it if missing. 4. Create or update .env.example with placeholder values for every variable in .env. 5. Check for any secret keys prefixed NEXT_PUBLIC_, VITE_, or similar browser-exposure prefixes and move the API call to a backend route. 6. List every hosting dashboard where I need to add environment variables for production. 7. Summarize every file you changed.
Paste this into Cursor, Claude, ChatGPT, Bolt, Lovable, or your AI coding tool.
Ready check
Beginner checklist
- Searched project for hardcoded key patterns (sk-, pk-, Bearer, api_key)
- All secrets read from environment variables, not string literals
.envfile exists in project root with real values.envis listed in.gitignore.env.exampleexists with placeholder values only- No secret keys use
NEXT_PUBLIC_orVITE_prefix - AI and payment API calls go through backend routes, not browser JavaScript
- Production keys added to hosting platform environment variables panel
- Test or sandbox keys used locally, not production keys
- Redeployed and tested that production API calls work
Frequently asked questions
- Can I just put my API keys in a config.js file instead of .env?
- No — any JavaScript file in your project is committed to Git and readable in the browser bundle. Use
.envand exclude it via.gitignore. Your code readsprocess.env.KEY at runtime. - Do I need to restart my local dev server after changing .env?
- Yes. Most frameworks read environment variables once when the process starts. After editing
.env, stop and restart your dev server for the new values to take effect. - My AI tool made the API call in a React component. Is that okay?
- Only if it uses a publishable or client-safe key explicitly designed for browser use. For OpenAI, Stripe secret keys, and most service credentials, the call must move to a backend route. Ask your AI tool to refactor it.
- What is the difference between .env, .env.local, and .env.production?
- Naming conventions vary by framework. In Next.js,
.env.localoverrides.envand is gitignored by default..env.production is loaded during production builds. Check your framework's documentation. For most projects, a single.env(gitignored) covers local development. - I deployed but my app says the environment variable is undefined. What now?
- The hosting platform is missing that variable. Open your hosting dashboard, find the environment variables section for your service, and add the missing variable with its production value. Trigger a redeploy — values are only injected when the app starts.