Replit app shows 404 on page refresh? Fix SPA routing
Short answer
- Single-page apps route in the browser. The server must answer unknown page paths with index.html.
- On an Express server, add a fallback after your API and static routes. On a Static deployment, add a rewrite in .replit.
- Keep real files (robots.txt, sitemap.xml) and /api routes out of the fallback.
Clicking around your app works. But refresh on /dashboard, or open a shared link, and you get Not Found or Cannot GET /dashboard. This is a classic single-page app (SPA) problem: the React router lives in the browser, and the server has no file called /dashboard. The fix is one fallback rule, placed in the right spot.
Symptoms
- Refreshing any page except the homepage returns 404, Not Found or
Cannot GET /path. - Links shared by email or social media land on an error page.
- It worked in the preview (dev server) but not after publishing.
- Search Console reports 404s for pages that exist in your app.
Likely causes
- The production server serves the built files but has no fallback to
index.htmlfor app routes. - The fallback is registered before the static or API routes, or is missing in the production branch of the server code.
- A Static deployment has no rewrite rule.
- The build output folder in the server code does not match where the build writes files.
Step-by-step fix
1. Find which server serves the app
Most Agent apps are an Express server that serves the built React files in production. A few are published as Static deployments. Open the publishing settings: the deployment type tells you which fix applies.
2. Express: add the fallback last
Order matters: API routes first, then static files, then the fallback for everything else that is a page request.
app.use("/api", apiRouter); // 1. API
app.use(express.static(distPath)); // 2. real files: JS, CSS, robots.txt
app.get(/^(?!\/api\/).*/, (req, res) => { // 3. app routes -> index.html
res.sendFile(path.join(distPath, "index.html"));
});
app.use("/api", (req, res) => res.status(404).json({ error: "Not found" }));The last line keeps unknown API paths as honest JSON 404s instead of returning your HTML page.
3. Static deployment: add a rewrite
Replit's static deployments support rewrites in .replit. Existing files are still served as themselves.
[[deployment.rewrites]]
from = "/*"
to = "/index.html"
4. Check the build path
Confirm the folder your server serves (dist, dist/public, build) is the one your build command writes to. A mismatch gives 404 on every page, including the homepage.
5. Republish and test deep links
Publish again and open three deep links directly in a private window.
Copy-paste prompt for Replit Agent
Open a new Agent chat (a fresh chat keeps old attempts out of its context) and paste this:
My published Replit app returns 404 / "Cannot GET" when I refresh or open a deep link like /dashboard. The homepage works.
Please fix routing in production only:
1. In the production server, register API routes first, then express.static for the build folder, then a fallback that sends index.html for any non-API GET request.
2. Make unknown /api/* paths return a JSON 404, not index.html.
3. Make sure robots.txt, sitemap.xml and other real files are still served as files with the correct content type.
4. Confirm the static folder path matches the build output.
Do not change the client-side routes or the dev server setup.How to verify the fix
curl -I https://your-app/dashboardreturns200withcontent-type: text/html.curl -I https://your-app/api/does-not-existreturns404with JSON.curl -I https://your-app/robots.txtreturnstext/plain, not HTML.- Refreshing any page in the browser keeps you on that page.
Serving index.html for every URL fixes refresh, but search engines still see the same empty page everywhere. For SEO, read why your Replit app is not indexed by Google.
FAQ
Why does refreshing a React page give 404 on Replit?
The browser asks the server for /dashboard, and the server has no such file. Client-side routing only works once index.html has loaded, so the server must answer page routes with index.html.
Will a catch-all route break my API?
It can if it is registered before your API routes or if it also catches /api paths. Register it last and exclude /api so missing endpoints still return 404.
Can Agent apps use a Static deployment?
Replit's docs say Static deployments are not compatible with Agent apps that need a backend server. Use Autoscale or Reserved VM for those.