What Is a .env File? API Keys in an AI-Built App
A .env file keeps API keys out of your app's code. See an env file example, what belongs in it and which keys you can use in the browser.
Overview & context
A .env file is a plain text file in your project's root that holds environment variables as NAME=value lines, usually API keys, service URLs and other settings. Your app reads them when it starts, so the values aren't in the source code. The catch: the .env file must never be committed to your repository and not every key in it is safe to use from the browser. Below you'll find an env file example, the difference between public and secret keys, where to store keys in production and what to do when a key leaks.
1. What a .env file is, with an example
A .env file holds settings that differ between environments: during development the app uses a test database and test services, once deployed to production it connects to live data and services. The source code stays the same and only the values in the file change. Besides API keys and passwords, put database URLs, credentials and other non-public values in the file too.
Vite and Next.js load .env files on their own. In Node.js, the dotenv package loads them, or since Node.js 20.6 the built-in --env-file flag. If you build the app with an AI assistant like Cursor or Claude Code, the assistant often creates the .env file for you and you fill in the values yourself, so the assistant doesn't know them. The example below is from an app that uses Supabase, Stripe and an email service.
# Database and sign-in (Supabase)
VITE_SUPABASE_URL=https://abcdefgh.supabase.co
VITE_SUPABASE_PUBLISHABLE_KEY=sb_publishable_...
SUPABASE_SECRET_KEY=sb_secret_...
# Payments (Stripe), test mode
VITE_STRIPE_PUBLISHABLE_KEY=pk_test_...
STRIPE_SECRET_KEY=sk_test_...
# Email
EMAIL_API_KEY=...2. Keep the .env file out of Git
Add .env to your .gitignore, so Git never commits it to the repository. Commit a .env.example file instead, with the same variable names, empty values and optionally comments that explain each setting. DevOps engineers and developers can then easily see which keys they need to set and for which services.
If an AI assistant writes your code, check after the first commit that the .env file really isn't in the repository. If it is, treat every key in it as exposed and follow section 5. For public repositories, GitHub scans for known key formats on its own, as described in its secret scanning docs.
.env
.env.local
.env.*.local3. Which API keys are safe in the browser
In the browser, your app can only use a public key that the service explicitly made for that purpose. With Vite or Next.js, for example, a variable with the VITE_ or NEXT_PUBLIC_ prefix gets embedded into the code that runs in the browser at build time and anyone who opens your app can read it. You'll find more in the Vite docs or the Next.js docs. That's why a secret key must never have one of these prefixes.
Most services issue both kinds of keys and you tell them apart by prefix or name. The table shows services that tools like Lovable or Bolt commonly use.
If the code your AI agent wrote calls OpenAI or another service directly from the app in the browser, anyone who opens your app can find the key and use it for their own purposes. Ask the AI agent to move the call into a server function, for example a Supabase Edge Function, and to store the key in that function's secrets.
| Service | Safe in the browser | Server only |
|---|---|---|
| Supabase | Publishable key (sb_publishable_), formerly the anon key, with Row Level Security enabled | Secret key (sb_secret_), formerly the service_role key |
| Stripe | Publishable key (pk_live_, pk_test_) | Secret key (sk_live_, sk_test_) |
| Firebase | Web app config including apiKey, data access is controlled by Security Rules | Service account key (JSON for the Admin SDK) |
| OpenAI, Anthropic and other AI services | No key | API key, calls go through a server function |
4. Where API keys go in production
In production, put API keys into the secret environment variables of the platform your app runs on and keep a copy in a password manager. The values are available to the platform and to you, but they aren't in any project file that someone could share by mistake or find in the Git history.
- 1
Hosting
In Vercel and Netlify, secret variables live in the project settings under Environment Variables. Set them separately for production and for preview deployments, so a preview doesn't use production keys.
- 2
Server functions
Supabase Edge Functions have their own secrets in the project settings. Put the keys for AI services and the Supabase secret key there.
- 3
CI/CD
In GitHub Actions, store keys as repository or environment secrets. A separate guide shows how to use them in a deployment workflow.
- 4
AI tools in the browser
In Lovable, Bolt and similar tools, enter keys in the secrets settings or connected services. Never type them straight into the chat, because chat messages are saved in the project history.
- 5
Password manager
Keep a copy of every key in a password manager, such as 1Password or Bitwarden, labeled with the service and the app. That way you won't have to dig up old keys or generate new ones when you move to another host.
5. What to do if an API key leaks
Revoke a leaked API key in the service that issued it first, then figure out where else it showed up. Deleting the key from your code or from a commit isn't enough, because anyone could have copied it in the meantime. And the leak doesn't have to happen on your side: in November 2026, for example, Trigger.dev disclosed that an attacker read environment variables of some of its customers.
- 1
Generate a new key and revoke the old one
Create a new key in the service settings and delete or disable the old one. This swap is called key rotation.
- 2
Update the key and redeploy
Put the new key into the platform's secrets, your local .env file and your password manager. The app reads variables when it starts, so restart it after the change.
- 3
Check the service usage
Go through the service's usage and billing for the time the key was compromised. With payment and AI services, look for unexpected charges or an unusual rise in requests.
- 4
Find other apps that use the same service
If more apps use the same service or the same key, rotate it in all of them. A list of services for each app helps you with that, see section 6.
6. Track services and keys per app in AboutTheApp
In AboutTheApp, record which services each app uses and where their keys are managed, not the keys themselves. In the product editor, click Add resource, pick the Security or DevOps & Infrastructure category and paste the URL of the service's API keys page, such as your Supabase project settings. In Description, note the variable names (SUPABASE_SECRET_KEY), where the key is stored (Vercel, password manager) and who owns the account in the service. Mark the resource Private, so only your team or someone with the unlock code can see it.
If a customer or an environment has its own keys, attach the resource to just that customer or environment. When a vendor reports a breach, type the address of the affected service into the dashboard search. You'll see every app, customer and environment that uses the service and where you need to rotate keys.
A private resource is hidden behind an unlock code, but it isn't a password vault. Never put the key itself into the resource URL or description. Keys belong in the platform's secrets and in a password manager.
Frequently asked questions
What is a .env file?
It's a plain text file in the project root with environment variables written as NAME=value, usually API keys and service URLs. The app reads it when it starts, so the keys aren't hard-coded.
How do I create a .env file?
Create a plain text file named .env in the project root and put one variable per line as NAME=value. You'll find the variable names in .env.example or in your framework's docs. Then add the file to .gitignore.
What is dotenv?
dotenv is a Node.js package that loads the variables from a .env file into process.env when the app starts. Since version 20.6, Node.js can do the same without it using the --env-file flag. Vite and Next.js load .env files on their own, so you don't need dotenv there.
Should I commit my .env file to Git?
No. The .env file belongs in .gitignore. Commit only .env.example with the same variable names and empty values, so the next developer knows what to fill in.
Is the Supabase anon key safe to expose?
Yes, as long as Row Level Security is enabled on your tables with policies that limit data access. The anon key and the newer publishable key are meant for the browser. The service_role key and the secret key never belong there, because they bypass all policies.
What do I do if I pushed an API key to GitHub?
Revoke the key in the service that issued it right away and generate a new one. Deleting the file or the commit isn't enough, since the key stays in the repository history and someone may have copied it already. Then check the service usage and store the new key in the platform's secrets.
How does Docker Compose use the .env file?
Docker Compose automatically reads the .env file from the folder with compose.yaml and substitutes its values into ${NAME} placeholders in compose.yaml. The variables only reach the container if you list them under environment or env_file.
Does AboutTheApp store API keys?
No. In AboutTheApp, you record the services each app uses, with a link to the page where the key is managed and a note on where the key is stored. The keys themselves belong in the platform's secrets and in a password manager.
In short
A .env file keeps keys out of your app's code and in production the platform's secret variables do the same job. If you also keep a list of services with links to their key settings for each app, a leak tells you right away which keys to rotate and in which apps.
Want an overview of the services behind every app?
Add your app to AboutTheApp for free and list its services with links to where their keys are managed.