Replit app works in preview but not deployed (404, blank page)
Symptoms
- The app runs perfectly in the workspace preview, deployment reports success, but the public URL returns a 404
- The deployed app shows a blank page
- The deployed app crashes with 'undefined' credential errors
- The deployment build fails with errors that never appeared in the editor
Why it happens
Workspace secrets do not carry over to deployments
App Secrets in the workspace and deployment secrets are separate stores, configured separately. Missing deployment secrets are the single most common cause of this failure, and they show up as 'undefined' credentials or crashes only in production.
The server binds to localhost or a hardcoded port
In a deployment, the server must bind to 0.0.0.0 on the assigned PORT environment variable. Code that hardcodes localhost or a fixed port works in the workspace and dies in the deployment.
Run command or entry point mismatch
The .replit run command or the deployment's configured entry point may not match how your app actually starts, so the deployment builds but never serves the right thing.
Wrong deployment type for the app
Static Deployments do not support runtime environment variables at all. An app that needs env vars or a server process needs Autoscale or Reserved VM instead.
Workspace-only values baked into the code
Variables like REPLIT_DEV_DOMAIN are undefined in deployments, and Agent-generated code sometimes hardcodes workspace-specific URLs or keys that break in production.
How to fix it
- Read the first error in the deployment logs, not the lastOpen the deployment's Logs tab and scroll to the earliest error. The real failure is usually the first one; everything after it tends to be fallout.
- Re-enter every required secret in the Deployment paneWorkspace App Secrets are a separate store from deployment secrets. Add every secret your app needs in the Deployment pane's Secrets section. This is the most common cause of preview-works-deploy-breaks, so do it even if you are sure you set the secrets already: you set them in the workspace, not the deployment.
- Bind to 0.0.0.0 and read PORT from the environmentMake sure the server listens on 0.0.0.0 and reads the PORT environment variable rather than hardcoding localhost or a fixed port. A localhost bind is invisible in the workspace preview and fatal in a deployment.
- Verify the run command and entry pointCheck .replit and the deployment settings to confirm the run/build commands and entry point match how your app actually starts. A stale command here produces builds that succeed and apps that never answer.
- Pick the right deployment typeIf the app needs runtime environment variables or a server process, use Autoscale or Reserved VM. Static Deployments do not support runtime env vars at all.
- Hunt down hardcoded workspace valuesSearch Agent-generated code for hardcoded URLs, keys, and REPLIT_DEV_DOMAIN, which is undefined in deployments. Replace them with environment variables; REPLIT_DOMAINS works in both the workspace and deployments.
- Redeploy after adding secretsSecrets are injected at deploy time, so adding them to an existing deployment does nothing until you redeploy.
How to prevent it
- Treat deployment secrets as a separate checklist item on every deploy; workspace secrets never carry over
- Always bind to 0.0.0.0 and read PORT from the environment from the first line of server code
- Use REPLIT_DOMAINS instead of REPLIT_DEV_DOMAIN so the same code works in both environments
- Review Agent-generated code for hardcoded URLs and keys before publishing
- Match the deployment type to the app: Autoscale or Reserved VM for anything with a server or env vars
Tools that actually fix this
Recommended because they address the failure mode above, not because of the payout. Some are affiliate links; see how we choose.
A purpose-built secret scanner covering 450+ key types. Its ggshield pre-commit hook blocks a key from ever being pushed, and history scanning finds the ones you already leaked. Free for individuals.
Try GitGuardian →All-in-one appsec (code scanning, dependencies, secret detection, containers) with low-noise output, built for small teams that cannot run five separate tools. One dashboard covers several failure modes.
Try Aikido Security →Frequently asked questions
Why does my Replit app return a 404 after deployment when the preview works?
The deployment environment differs from the workspace: secrets are a separate store, the server must bind to 0.0.0.0 on the assigned PORT, and the run command or entry point may not match your app. Check the deployment Logs tab for the earliest error, then work through secrets, port binding, and run configuration in that order.
Do workspace secrets carry over to Replit deployments?
No. Workspace App Secrets and deployment secrets are separate stores, and missing deployment secrets are the most common reason an app works in preview but crashes with 'undefined' credential errors in production. Re-enter every required secret in the Deployment pane's Secrets section, then redeploy, because secrets are injected at deploy time.
Which Replit deployment type supports environment variables?
Autoscale and Reserved VM deployments support runtime environment variables; Static Deployments do not support them at all. If your app needs env vars or a running server process, deploy it as Autoscale or Reserved VM rather than Static.
Why are my credentials 'undefined' in the deployed Replit app?
Either the secret was set in the workspace but never added to the deployment's separate Secrets section, or the code references a workspace-only variable like REPLIT_DEV_DOMAIN, which is undefined in deployments. Add the secret in the Deployment pane and redeploy, and use REPLIT_DOMAINS where you need a domain value that exists in both environments.
Sources
- Replit docs: Deployments troubleshooting
- Replit forum: App works in dev mode, not in deployed mode
- Replit forum: Why the deployment is not equal to the preview
- AppStuck: Replit not working, 10 common errors and how to fix them
Related errors
v0 environment variables undefined: API routes 500 in production but work in preview
Lovable white screen: blank preview or published app shows nothing
Replit database empty after deploy: where did my data go?
v0 deployment stuck on 'Deploying' (or 'Failed to fetch deployment status')
Bolt.new + Supabase: 403 Forbidden, data not saving, or the wrong project connected
The Vibe Oops briefing
One email when something ships to production that should not have. New incidents, new error guides, no filler.