Deployment

Replit secrets not working in deployment? How to fix it

Short answer

  • The published app reads its own set of deployment secrets. Check each key in the Secrets section of the Publishing pane, not only in the workspace.
  • A secret can be unsynced or overridden with a different value for the deployment. New values apply only after you publish again.
  • Frontend variables (VITE_…) are baked in at build time, and Static deployments do not get secrets at all.

The error says DATABASE_URL environment variable is not set, or your OpenAI calls fail with 401, but only in the published app. The key is right there in Secrets. What is going on? Replit has two places a secret can live: the workspace (for the preview) and the deployment (for the published app). Replit's docs describe deployment secrets as synced from the workspace when you publish, yet any key can be unsynced or given a different value. Here is how to make the live app see the right values.

Symptoms

  • Logs show undefined, is not set or Missing API key for a key you added.
  • Third-party calls fail with 401 or 403 only in production.
  • A warning in deployment secrets that the value differs from the workspace value.
  • You changed a key, but the live app still uses the old one.

Likely causes

  1. The key exists in the workspace but is missing or unsynced in the deployment secrets.
  2. The deployment has an override with an old or test value.
  3. You changed the secret but did not publish again, so the running deployment still has the old value.
  4. The variable is used in frontend code and was not present when the frontend was built.
  5. The app is a Static deployment, which does not support secrets.
  6. The code reads a slightly different name (OPENAI_KEY vs OPENAI_API_KEY).

Step-by-step fix

1. List what the code expects

Search the project for process.env. (Node) or os.environ (Python). Write down every name. This is the list the published app needs.

2. Check the deployment secrets

Open Publishing, then the Secrets section. For each name, confirm it exists, that it is synced or deliberately overridden, and that production uses live keys (Stripe sk_live_) while development uses test keys. Remove stale overrides you no longer need.

3. Fail loudly at startup

Add a check that logs which keys are present, never their values, and stops the app if a required one is missing. The next deploy then tells you exactly what is wrong.

const required = ["DATABASE_URL", "SESSION_SECRET", "STRIPE_SECRET_KEY"];
for (const k of required) console.log(`${k} present:`, Boolean(process.env[k]));
const missing = required.filter((k) => !process.env[k]);
if (missing.length) throw new Error(`Missing secrets: ${missing.join(", ")}`);

4. Publish again

Running deployments do not pick up new values. After any secret change, select Publish again so a new deployment starts with the new values.

5. Handle frontend variables separately

Code that runs in the browser cannot read server secrets at runtime. Vite only exposes variables prefixed with VITE_, and only those present at build time. Never put a secret key in one: anything in the bundle is public. Move the call to a backend route. See Vite environment variables undefined on Replit.

Copy-paste prompt for Replit Agent

Open a new Agent chat (a fresh chat keeps old attempts out of its context) and paste this:

Secrets work in the Replit workspace but not in my published app.
1. List every environment variable the code reads, with the file where it is used, and mark which are used in browser code.
2. Add a startup check that logs "<NAME> present: true/false" for each required server variable (never print values) and exits with a clear error if one is missing.
3. Move any secret used in frontend code to a backend API route.
4. Do not hard-code any key, and do not paste key values in this chat; I will set them in the deployment secrets myself.
Then tell me the exact list of keys I must check in Publishing > Secrets before republishing.

How to verify the fix

  • After republishing, the deployment logs show present: true for every required key.
  • The feature that failed (payments, AI calls, database) works on the live URL.
  • Searching the live site's JavaScript in DevTools for the first characters of your keys finds nothing.

For how to store keys safely in the first place, read Replit Secrets: how to store API keys safely.

FAQ

Do Replit workspace secrets carry over to the deployment?

Replit's publishing docs say secrets sync from the workspace when you publish, but each key can be unsynced or overridden for the deployment, and some help pages describe them as separate stores. Always check the Secrets section of the Publishing pane before you rely on a value.

Why is my new secret value not used by the live app?

The running deployment keeps the values it started with. Publish again after changing a secret.

Can a Static deployment use Replit Secrets?

No. Replit's docs list Secrets as available for every deployment type except Static. A static site has no server to keep a secret, so call protected APIs from a backend instead.

Get a free audit