Replit Secrets: how to store API keys safely
Short answer
- Put every key, token and password in the Secrets pane and read it as an environment variable. Never paste real keys in code or in Agent chats.
- A secret on the server is safe. The same secret used in frontend code is public. Call third-party APIs from a backend route.
- If a key was ever in your code, its history or the browser, rotate it. Deleting the line is not enough.
Exposed API keys are one of the most common, and most expensive, mistakes in AI-built apps. A leaked OpenAI or Stripe key can be abused within hours. Replit gives you a simple tool to avoid it: Secrets. Here's how to use it properly.
How Replit Secrets work
- You add a name and value in the Secrets pane of your project.
- Your code reads it as an environment variable at runtime.
- Secrets are stored encrypted and are not written into your source files.
Reading secrets in code
Node.js
const apiKey = process.env.OPENAI_API_KEY;
if (!apiKey) throw new Error("OPENAI_API_KEY is not set");
Python
import os
api_key = os.environ.get("OPENAI_API_KEY")
if not api_key:
raise RuntimeError("OPENAI_API_KEY is not set")
Failing loudly at startup when a secret is missing saves you from confusing errors later, especially after publishing.
The big trap: secrets in the browser
A secret is only secret while it stays on the server. If frontend code uses it, it is sent to every visitor. This happens often with AI-generated code that calls OpenAI, Stripe or Google APIs directly from React.
// Frontend: never do this
fetch("https://api.openai.com/v1/...", {
headers: { Authorization: `Bearer ${OPENAI_KEY}` },
});
// Frontend: call your own backend instead
fetch("/api/generate", { method: "POST", body: JSON.stringify({ prompt }) });
// Backend route: the only place that uses the key
app.post("/api/generate", requireLogin, rateLimit, async (req, res) => {
// call the provider with process.env.OPENAI_API_KEY
});
Test it: open your published app, open DevTools, and search the Sources and Network tabs for the first characters of your key. If you find it, move the call to the backend and rotate the key.
Secrets and Replit Agent
- Never paste real keys into the Agent chat. Add them in the Secrets pane and tell Agent the variable name.
- After Agent adds an integration, check where the key is used. Make sure it is only read on the server.
- Use keys with the minimum permissions and a spending limit at the provider, so a mistake stays small.
Secrets in production
- Confirm your published app has every secret it needs in its publishing settings.
- Use live keys in production and test keys in development (Stripe, email providers).
- Name secrets clearly:
STRIPE_SECRET_KEY,STRIPE_WEBHOOK_SECRET,DATABASE_URL.
If a key was exposed
- Revoke or rotate it at the provider right away.
- Create a new key and store it only in Secrets.
- Check the provider's usage and billing logs for activity you don't recognize.
- Find how it leaked (code, history, frontend bundle, a shared screenshot) and fix that path.
Secrets are check 1 to 3 of our Replit Agent security checklist. Get your overall score with the free Replit Readiness Score.
FAQ
Where do I put API keys in Replit?
In the Secrets pane of your project. Each secret becomes an environment variable your code reads at runtime, for example process.env.OPENAI_API_KEY in Node.js or os.environ['OPENAI_API_KEY'] in Python.
Are Replit Secrets visible to other people?
Secrets are stored encrypted and are not shown in the code editor or included in the code itself. Anyone with edit access to the project and your running app code can still use them, so limit collaborators and give keys the minimum permissions.
Does my published app get my secrets?
Check the publishing settings of your app and confirm every secret the production app needs is present. Use live keys in production and test keys in development.
What should I do if I committed an API key?
Revoke or rotate the key at the provider immediately, create a new one, store it in Secrets, and check the provider's usage logs for unexpected activity. Removing it from the code does not remove it from history.