The direct answer: a secret API key belongs in protected server-side settings supplied by your host, or in a dedicated secrets manager. Your server reads it when it needs to call a provider. It should never be shipped to a visitor's browser, committed to GitHub, pasted into a public prompt or baked into a container image.
First, work out whether the key is actually secret
An API key is a string that lets software identify itself to a service. Some keys are deliberately publishable; others can spend your money, read data or perform privileged actions. A Stripe publishable key, for example, is meant for certain browser tasks. A Stripe secret key is not. Look up the provider's description before deciding where a value goes. If the provider calls it secret, private, admin or server-side, treat it as a secret.
Names alone are unreliable. A variable called PUBLIC_API_KEY does not become safe because someone added “public” to its name. The real test is what that key can do and whether the provider permits browser exposure.
The route a secret should take
In a simple app, the flow is: a user presses a button; the browser asks your server to do a specific job; the server reads its secret from protected settings; the server calls the outside service; and the browser receives only the result it is allowed to see. The browser never receives the secret itself.
This matters for AI features. If the browser calls an AI provider directly with your private key, anyone who loads the page may be able to extract the key and use your account. Your server should check who is asking, limit the work and make the provider call on their behalf. The same pattern applies to payment, email and database credentials.
Where to put it in development and production
For local development, a .env file is common. Keep it on your device, add the real file to .gitignore, and use a separate .env.example containing names and harmless placeholders so collaborators know what is required. Check whether the file was committed before adding an ignore rule: ignoring it later does not erase its history.
For production, open the hosting service's secret or environment settings and set the value for the server runtime. Use separate test and live keys where the provider offers them. A dedicated secrets manager is another option for teams or systems with stricter access and rotation needs. Avoid putting literal secrets in a Dockerfile, build argument, frontend environment variable or deployment script committed to the repository.
Environment settings are a delivery mechanism, not magic protection. People with access to the host, server process, logs or debugging tools may still be able to see values. Give access only to those who need it, and avoid printing the key in errors or logs.
How to check an AI-built app without being an engineer
- Make an inventory. List the services the app uses: AI, payments, email, storage, maps and database. For each, record whether its key is publishable or secret, who owns the account and whether it is test or live.
- Ask where each secret is set. You should be shown the name of the server-side setting and the server code that reads it, without anyone showing you the value itself.
- Inspect the public output. Ask a technical helper to check the deployed page and downloadable JavaScript for secret key values or suspicious key prefixes. Do not paste the values into a public scanner.
- Check the repository and logs. Search current files and Git history for credentials, and confirm application logs do not print them. GitHub's secret scanning may help when available, but it cannot prove every secret is absent.
- Test a safe failure. In a non-production environment, confirm the feature fails clearly if the secret is missing and that the error shown to users does not reveal the value.
If a key has already leaked
Assume the old value can be used by someone else. Revoke or rotate it through the provider first, set the replacement in the correct server setting, deploy or restart as required, and test the affected feature. Check the provider's usage records for unexpected requests or charges. Removing the visible text is still useful, but it does not disable a copied key. Rewriting Git history is a separate, carefully coordinated decision and should not delay revocation.
The urgency depends on what the key can access. A payment secret or broad database credential can have a different impact from a restricted, short-lived token. Write down what the exposed key could do and what you checked. If customer data may have been accessed, get appropriate incident and legal advice for your situation.
Make future leaks less costly
Use separate keys for development and production, grant only the permissions needed, and set spending or usage limits where available. Know who can rotate each key and what breaks when it changes. Review access when a collaborator leaves. A simple private inventory beats trying to remember every provider when something goes wrong.
This guidance follows the OWASP secrets management guide, GitHub's advice on exposed repository secrets, and the key-handling guidance from Stripe and OpenAI.
Where Ship Doctor fits
KHDS Ship Doctor helps vibe coders inspect the actual project, trace where secrets are read and document what remains unverified. Its free builder creates a starter instruction; the £49 one-off toolkit adds reusable checks, evidence templates and a remediation plan. The public sample report shows the evidence-led format. For the wider launch picture, see the non-technical founder checklist and vibe coding security checklist.
Frequently asked questions
Where should I put an API key in a vibe-coded app?
Put a secret key in the host's protected server-side settings or a secrets manager, and read it only in server code that needs it.
Is a .env file safe for production secrets?
It can help local development if it stays out of Git. Use protected server settings for the deployed app and verify that the server reads them.
Can users see an API key in browser code?
Yes. Treat everything delivered to the browser as public, including bundled JavaScript and public build variables.
What if I already committed an API key to GitHub?
Revoke or rotate it first, update the app, and check for misuse. Removing text from the repository does not invalidate the old key.
Check the project you actually built
Find exposed secrets before users do.
Create a free starter instruction or use the complete reusable Ship Doctor toolkit.