©Code byMilanParmar

Replit app works in preview but not when published

How to tell whether a published Replit app fails at the build, at startup, or on live requests, the fix for each cause with the code and settings to change, a symptom table, and a checklist to run before every publish.

12 min read

An unlit white pillar candle standing on a desk

A Replit app works in preview but not when published because the published app is a separate copy with its own settings. Its secrets, its database, its run command, its port, and its deployment type are all set apart from the workspace. One of them is missing or different, and the publishing logs say which.

The preview only proves the code runs inside the workspace. Replit's own troubleshooting guide puts it in one line: a working Preview does not verify production configuration. This guide starts from what you can see, a failed publish or a live address that errors, and works out which setting is wrong. It's written for the founder who built the app with Replit Agent, and for the developer helping them. Every Replit behaviour described here comes from Replit's docs, checked in November 2026.

Why a Replit app works in preview but not when published

When you select Run in the workspace, the app starts with the workspace's secrets, the development database, and a replit.dev address. When you publish, Replit builds a fresh copy and runs it at a replit.appaddress. That copy shares your code and little else. Replit's docs list what to compare between the two: the build and run commands, production secrets, which database is selected, and the login configuration.

Six differences cover the causes Replit's docs list, and each has its own section below.

  • Secrets. Secrets set in the workspace are not copied to the published app.
  • Host and port. The published server must accept outside connections on the port Replit expects.
  • The health check. Replit requests your homepage before it marks the app live.
  • The run command. The published app needs a command that starts a server and keeps running.
  • Deployment type. A Static deployment has no server behind it.
  • The database and the disk. The published app reads a production database, and its file system resets on every publish.

If the app publishes and loads but the records are gone, that last one is your problem, and it has its own guide: a Replit app that lost data after publishing. The rest of this post is for an app that won't publish, or publishes and errors.

Find where the published Replit app fails: build, start, or requests

Replit's deployment troubleshooting guide says to identify the failing phase first: building, starting, or serving requests. Each phase has different causes, so this step decides which section you need.

  1. Rule out Replit.Open status.replit.com. If there's an incident on publishing, wait for it.
  2. Confirm the preview really works. Select Run and check the app loads at its replit.devaddress. The docs are blunt that publishing won't repair a broken preview.
  3. Open the logs. In the Publishing pane, open the Logs tab. For a failed publish, the docs say to find the deployment under Publishing, then History, and open its logs from the three-dot menu.
  4. Find the first error, not the last.Replit's docs say the first line marked ERROR or FAILED is usually the root cause, and the lines after it are usually knock-on effects. Copy that line before you change anything.
  5. Keep the logs.The docs say to keep a failed deployment's logs before retrying, and not to republish an unchanged build. A second identical failure tells you nothing.
What you see when a Replit app fails after publishing, the phase, and where to look
What you seePhaseUsual cause
Publish stops with a failed buildBuildBuild command, a missing package, or a missing variable
"No run command configured"BuildRun command not saved in the publishing settings
Build passes, publish fails at the final stepStartServer on localhost, wrong port, or a homepage slower than five seconds
"Application failed to respond"StartApp not listening on the port Replit expects
Internal Server Error, 500, or 502RequestsA crash in the app: missing secret, database, or a localhost URL
Blank page, or pages load but nothing savesRequestsStatic deployment chosen for an app that needs a server
Only login or payments failRequestsRedirect and webhook addresses still point at the preview
Slow first load, then fineNoneAutoscale starting from zero servers. Normal

Replit publishing fails during the build

A build failure means Replit couldn't turn your code into something it can run. Replit's docs say most build failures come from missing dependencies, an incorrect run command, or a failed database migration.

Check the build and run commands

Open the Publishing pane and read both commands. The docs name the usual faults: typos, incorrect flags, the wrong entry file, and commands that only worked in the workspace. An app that needs a build step, such as a React front end, needs both a build command and a start command set there.

"No run command configured"

This one can appear even when a run command is set. Replit's fix is to disconnect the run command in the deployment settings, add it again, save, and publish again.

Variables the build needs

Some apps read a variable while building, such as an API address baked into the front end. If that variable exists only in the workspace, the build fails or produces a front end pointing nowhere. The docs say to check whether required environment variables are set for publishing.

A publish stuck on build or migration

Replit's docs give a reset: press Cmd+K on a Mac or Ctrl+K on Windows, search for Restart compute, run it, then select Publish. If it sticks again, that's a support ticket with the full build log attached.

Replit publish fails at the last step: host, port, health check

This failure is confusing because the build log is clean. The code built, the server started, and Replit still couldn't reach it. There are four causes, and one app can have more than one of them.

The server listens on localhost

Replit's docs say the server must listen on 0.0.0.0, and that listening only on localhost or 127.0.0.1does not work for published apps. Localhost means "only this machine may connect". Many frameworks default to it during development, which is why the preview can work while the published app can't be reached.

The port is hard-coded

"Application failed to respond" means, in Replit's words, that the app isn't listening on the port Replit expects. The docs' fix is to read the port from the PORT environment variable instead of a fixed number.

Node and Python: listen on 0.0.0.0 and the PORT variable
// Node (Express)
const PORT = process.env.PORT || 3000;
app.listen(PORT, "0.0.0.0");

# Python (Flask)
port = int(os.environ.get("PORT", 3000))
app.run(host="0.0.0.0", port=port)

The .replit file exposes the wrong ports

Replit can detect your server's port by itself. But the docs say that once ports are defined in the .replit file, automatic detection is off, externalPort must be 80 for the publish to pass, and the server must listen on the matching localPort. Autoscale and Reserved VM deployments also support only one exposed port. The ports guide warns that if you expose more, or expose a single port on localhost, the published app will fail. Open .replit, check whether more than one port entry has built up, and leave one:

.replit: one exposed port for a published app
[[ports]]
localPort = 5000
externalPort = 80

The homepage is too slow, or the program exits

Before marking the app live, Replit sends an HTTP request to it. The docs say that if the homepage takes more than five seconds to respond, the health check can time out and publishing fails at the final step. An app that loads a large file, calls an AI model, or runs a heavy query on the homepage fails here. Move that work behind a user action or cache it. Don't remove a login check to get past the health check; the docs warn against exactly that. The published app also has to be a program that keeps running. A script that does its job and exits gets restarted over and over.

Secrets missing from the published Replit app

Replit keeps two sets of secrets. Its docs say development secrets are only available in the editor, the published app reads from deployment secrets, and changing one store doesn't update the other. So an API key you gave Agent while building is not in the live app unless you also added it for publishing.

The docs list what a missing secret looks like: errors about undefined values, failed API calls, database connection failures, login errors, and payment failures. In the log it's often a line saying a variable is undefined, right before the crash.

  1. Open the Secrets tool in the workspace and write down every name. Names only, not values.
  2. Open the Publishing pane and compare its secrets against that list. Add what's missing.
  3. Use live values where the service has a test mode and a live mode. With a Stripe test key, the published app shows a working checkout and takes no real money.
  4. Select Publish. The docs say new values only go live when you publish again after updating the deployment secrets.

Never paste a secret's value into the Agent chat to "help it debug". If one has already been pasted there or into front-end code, replace it at the service that issued it.

Published Replit app returns 500, 502, or Internal Server Error

The app published, and the live address shows an error. Replit's docs say an Internal Server Error on a successfully published app comes from your app's code, not Replit's infrastructure, and that a 502 usually means the app process crashed. They also say a 500 or 502 is a symptom, not proof of a specific cause. So reproduce one failing request, note the time and the address, and read the runtime log around that minute.

Hard-coded localhost addresses

If the front end calls http://localhost:3000/api/…, it works in the workspace and fails for every visitor. The docs say to replace localhost and 127.0.0.1 references with relative addresses such as /api/orders, or ones built from environment variables. The same applies to an app that calls its own public address from the server: use a relative path.

The database isn't ready

Replit's docs say to confirm DATABASE_URL points at the production database, and to run pending migrations, the scripts that create or change tables, against production before publishing. A table that exists in development and not in production gives a 500 on the first page that reads it.

Reading restarts in the log

The docs explain two lines that worry people. SIGTERM means a graceful stop and is normal: Autoscale restarts regularly by design. Exit code 1 means the process crashed, and the cause is in the lines just before it.

Going back to the last working version

If real users are affected, open Publishing, then History, and redeploy the last version that worked. Check one thing first. The docs warn that redeploying code is not a database restore, and that an older version may not match the current database structure. If the broken release added or removed columns, the old code can fail in a new way.

Blank page or missing API: the wrong Replit deployment type

Replit has four deployment types, and picking the wrong one produces an app that publishes without errors and still doesn't work.

Replit deployment types and what each one can't do
TypeWhat it runsWhat goes wrong
AutoscaleA web server that grows under load and drops to zero when idle. The defaultFirst request after a quiet period takes a few seconds
Reserved VMOne dedicated server that never sleeps, at a fixed monthly costCosts the same with no traffic
StaticHTML, CSS, and JavaScript files onlyNo server, so no API routes, logins, or database calls
ScheduledA command on a timer, then it stopsNo web page and no public address

Replit's docs say Static deployments are not compatible with apps created using Agent, because those need a back end. If the live site shows a blank page, or pages appear but forms and logins do nothing, check the type in the Publishing pane and change it to Autoscale. If the app really is static files, the other common cause the docs name is an incorrect public directory.

Slow first loads are a type question too. The docs call the delay on an Autoscale app's first request after scaling to zero a normal cold start. If the app has to stay connected, as a chat bot does, or runs memory-heavy background work, the docs point to a Reserved VM. A job that should run every night belongs in a Scheduled deployment, not in a timer inside a web app that may be asleep.

Login, payments, or CORS broken only on the published address

Sometimes the published app loads and one feature fails. That feature almost always depends on the app's address, which changed from replit.dev to replit.appor your own domain. For an app that publishes but breaks, Replit's docs list the settings to compare:

  • Login callback or redirect URLs. Google sign-in and similar providers only send users back to addresses on their allowed list. Add the published address there.
  • Payment webhook or redirect settings. Stripe sends payment events to an address you registered. If that is still the preview address, payments succeed and your app never hears about them.
  • API allowlists and CORS.CORS is the browser rule that stops one site calling another without permission. If the front end and back end are the same app, the docs say to use relative addresses. If they're separate, allow the published front end's address on the back end, and only that.
  • Files written to disk. The docs say the published file system resets on every publish, so uploads saved to a folder disappear. They belong in a database or storage service.

Test each of these on the published address, signed out, in a private window. That is how a new visitor meets the app.

Replit pre-publish checklist

Run this before every publish that matters. It takes ten minutes, and each line maps to a failure above.

Don't skip the last line. Publishing completing is not the same as the app working: Replit's own completion list ends with the main flow working at the public address and the logs showing no hidden startup errors. For the wider set of checks before real users arrive, from backups to who owns the accounts, use my vibe-coded app launch checklist.

When to get a developer for a Replit app that won't publish

Fix it yourself when the log names the problem: a missing secret, a port entry, the wrong deployment type. Those are settings, and the sections above cover them. Get a developer when the first error line points into code you can't read, when each Agent fix moves the failure somewhere new, or when the app publishes and real users hit errors you can't reproduce. If you're choosing someone, how to hire a developer to fix an AI-built app covers what to ask and what access to give.

For an app with users or payments, I start with a Launch-Ready Review: $900–1,500 and three to five days, ending in a written report with a fixed price for each fix. The fixes themselves, plus a proper deploy and monitoring, are a Production Sprint at $3,000–7,500. What sets the price inside those ranges is in the cost to fix a vibe-coded app.

Two projects show what the larger version looks like. The Chat Company came to me as a buggy demo the founder had generated with AI tools. I kept about 20% of the code, rewrote the rest, and launched in nine weeks for $20,000. It now serves 30+ businesses and handles 100K+ messages a day. On the social challenge app, an agency had left AI-generated code half-built, with security, login, and payment problems. I kept what was solid, rewrote the rest, and launched in eight weeks for $16,000. It now has 10,000 users.

If your published Replit app is failing and the log doesn't make sense, send me the first error lineand the app's link. I'll reply with which phase is failing and what I'd change.

Sources

  1. Troubleshoot publishing: logs, secrets, 0.0.0.0, ports, the five-second health check, Static deployments, Replit Docs
  2. Troubleshoot deployments: the build, startup, and serving phases; preview versus published, Replit Docs
  3. Deployment and publishing FAQ: run command, Internal Server Error, restarts, secrets, History, Replit Docs
  4. Networking and app errors: Application failed to respond, 502, 403, localhost URLs, migrations, Replit Docs
  5. Ports: localPort and externalPort, one exposed port for Autoscale and Reserved VM, Replit Docs
  6. Deployment types: Autoscale, Reserved VM, Static, and Scheduled, Replit Docs
Milan Parmar

The developer

Freelance full-stack developer in Bengaluru with 5+ years of experience. I redesign websites, take over broken apps, and build SaaS products, with 18 case studies to show for it.

FAQs

Why did my Replit app's address change after republishing?

Replit's docs say the replit.app subdomain comes from the project name, and it may change if you unpublish and publish again, especially after a rename. Renaming the project back to the original name and republishing may restore it, but Replit can't reassign a released subdomain by hand. A custom domain is the permanent fix, because it stays the same across every publish.

Can I change the region of a published Replit app?

Not in place. Replit's docs say you can't change the publishing region or the database region of an existing app. You remix the app and publish the remix in the new region. The remix may get a different replit.app address and needs its deployment secrets added again, so connect a custom domain first if people already use the old address.

Does shutting down a published Replit app delete it?

No. Replit's docs say shutting down a deployment takes the app offline and stops deployment charges, while your files, code, and databases are kept. Custom domain connections tied to that deployment are removed, so you add them again when you republish. An Autoscale app already drops to zero servers without traffic, so you may not need to shut it down at all.

Why does my published Replit app return 403 Forbidden?

Replit's docs give three common causes. The request headers are too large, usually from too many cookies, so clear cookies for the domain and test again. The request is missing a login token or session the app requires. Or the app is set to restrict access, as a private deployment does. The deployment logs show which one applies.