Skip to content
CodeLifter
Search/ Browse prompts
CodeLifter Forum

How do you keep API keys out of a vibe-coded app?

Staff answerWritten by CodeLifter editors · Vibe coding prompts2 repliesupdated

Short answer

Keep secret API keys on a server and out of anything the browser downloads. Store them in environment variables or a secrets vault, list .env files in .gitignore, tell the assistant in your rules file never to hard-code keys, scan every commit for secrets, and rotate any key that has ever been pushed or shipped.

Written by CodeLifter editors · Staff, CodeLifter ·
CiteCodeLifter Forum, "How do you keep API keys out of a vibe-coded app?", https://codelifter.com/forum/posts/how-do-you-keep-api-keys-out-of-a-vibe-coded-app/, accessed 2026-11-12.
  1. Staff, CodeLifter ·

    Why is a key in front-end code public?

    Front-end code is the JavaScript your site sends to every visitor's browser, and anyone can open it. Build tools copy some environment variables straight into that code, so "it was in an environment variable" does not mean it stayed private.

    The Vite documentation (v8.3.4, read 16 October 2026) says variables prefixed with VITE_ "will be exposed in client-side source code after Vite bundling" and that "VITE_* variables should not contain sensitive information such as API keys. The values of these variables are bundled into your source code at build time." Next.js (page last updated 25 August 2026) does the same with the NEXT_PUBLIC_ prefix: the value is inlined "into any JavaScript sent to the browser."

    This is the trap in vibe-coded apps. You ask for a page that calls an AI or payment API, the assistant makes the call from the browser because that is the shortest route, and the key goes out with the page. Simon Willison's post on vibe coding puts it plainly: if your code involves secrets, you need to understand how it works to avoid exposing them.

    Which keys are safe to expose?

    Some services issue two kinds of key on purpose: a public one for the browser and a secret one for the server. Stripe's API keys page (read 16 October 2026) is a clear example:

    Key or variable Safe in the browser? Source
    Stripe publishable key pk_... Yes; it "can't perform sensitive operations such as creating charges" Stripe docs
    Stripe secret key sk_... No; "unrestricted permissions on all Stripe APIs" Stripe docs
    Stripe restricted key rk_... No; permissions you control, still server only Stripe docs
    Vite VITE_NAME Only if the value is not secret Vite docs
    Vite NAME without the prefix Not exposed to client code Vite docs
    Next.js NEXT_PUBLIC_NAME Only if the value is not secret Next.js docs
    Next.js NAME without the prefix Server only by default Next.js docs

    Most AI model APIs issue only secret keys. If the provider's docs do not say a key is safe to expose, treat it as secret.

    How do you move the key to the server?

    1. Find every key. Search the project: grep -rnE "sk_|api[_-]?key|secret|token|password" --exclude-dir=node_modules .
    2. Create a server route. A small function on your host (a serverless function, which is code the host runs on request without you managing a server) receives the browser's request, adds the key, calls the API and returns only the result. In Next.js that is a Route Handler such as app/api/route.js, which can read process.env.MY_KEY.
    3. Put the key in the host's secret settings, or in a local .env file for development. Stripe's advice is to use a secrets vault where your platform offers one, and environment variables if not, and not to put keys "in source code or configuration files checked into version control."
    4. Ignore the env files. Add .env and .env*.local to .gitignore. Vite's docs say .env.*.local files "can contain sensitive variables" and should be ignored, and Next.js notes that create-next-app adds .env files to .gitignore for you.
    5. Rebuild and check the bundle. Build the site, then search the output folder (dist/ or .next/) for the first characters of your key. No match is the result you want.
    6. Limit the key. Give it the fewest permissions the job needs and a spending limit where the provider offers one, so a leak costs less.

    What should you tell the assistant?

    Put the rule where every session reads it, such as AGENTS.md (see what goes in a rules file):

    ## Secrets
    - Never write an API key, token or password in code, config or tests.
    - Call paid or secret-key APIs only from server code; the browser calls our own route.
    - Never use the VITE_ or NEXT_PUBLIC_ prefix for a secret.
    - Read secrets from environment variables and name the variable you need.
    

    Also keep secrets out of the folders an agent can read. An assistant connected through the Filesystem MCP server can open an .env file like any other; the Filesystem sandbox thread covers that.

    How do you catch a key before it is pushed?

    • Push protection. GitHub's push protection docs say the feature "blocks pushes that contain secrets before they reach your repository." Push protection for users is on by default and "Stops you from pushing secrets to public repositories on GitHub." Repository-level push protection is off by default and needs GitHub Secret Protection.
    • A local scanner. Gitleaks scans a repository's history with gitleaks git -v and can run as a pre-commit hook. Its README says the project is now feature complete and will get security patches only.
    • Your own eyes. GitHub suggests git diff --cached to review exactly what a commit will contain, and avoiding git add . so stray files are not swept in.

    The CodeLifter desk article on vibe coding security has the wider routine.

    Short version

    • Anything in the browser bundle is public, including VITE_ and NEXT_PUBLIC_ variables.
    • Call secret-key APIs from a server route; the browser calls your route.
    • Keep keys in a vault or environment variables, and .env files in .gitignore.
    • Put a no-secrets rule in AGENTS.md and turn on push protection or a scanner.
    • If a key was ever pushed or shipped, rotate it.
    0
    ReplyLink

Plain text or simple Markdown. Links are nofollow. Your email is never shown.

  1. CodeLifter editorsStaffStaff, CodeLifter ·

    What should you do if you pushed an API key to GitHub? Revoke or rotate the key first, before anything else. GitHub's page on removing sensitive data says that once a secret is revoked or rotated "it can no longer be used for access, and that may be sufficient to solve your problem." Deleting the file in a new commit does not help, because the key stays in the history. Rewriting history is possible but costly. GitHub lists the side effects: changed commit hashes, broken diffs on closed pull requests, lost commit signatures, and a high risk that someone's old clone pushes the secret back. Its procedure uses git-filter-repo version 2.47 or later with the --sensitive-data-removal flag, followed by git push --force --mirror origin. Copies in forks and other people's clones stay where they are, and GitHub Support will only purge cached views when rotation cannot fix the risk. Some providers make rotation painless: Stripe's docs say that when you rotate a key in the Dashboard, the old and new keys both work for up to 7 days while you switch over. Then check the provider's logs for calls you did not make.

  2. CodeLifter editorsStaffStaff, CodeLifter ·

    Is it safe to keep API keys in a .env file? It is the normal place for development keys, with three conditions. First, the file must not be committed. Add it to .gitignore before you create it, and check with git status that it does not appear. Vite's docs mark .env.local and .env.[mode].local as "ignored by git" in their file list, describe the .local files as able to "contain sensitive variables", and recommend adding *.local to .gitignore. Second, the variable must not carry a public prefix. In Vite, only VITE_ variables reach client code; DB_PASSWORD in the docs' example comes back undefined in the browser. Third, remember the file is plain text on your disk, readable by any program or agent with access to the folder. For production, Stripe's key guidance prefers a secrets vault from your hosting platform and treats environment variables as the fallback. Next.js also documents a load order worth knowing: process.env first, then .env.$(NODE_ENV).local, .env.local, .env.$(NODE_ENV) and .env, stopping at the first match. So a value set on your host overrides the one in your local file, which is what you want in production.

CodeLifter

Reviewed vibe coding prompts, the JavaScript each one should produce, and sourced answers on AI-generated code: who wrote it, who owns it, and whether you can ship it. Free since 1999.

Browse the Prompt Shelf

Popular topics

© 1999 to 2026 CodeLifter

Independent. No ties to any software vendor.
Code MIT Text CC-BY-4.0 Back to top