404 on page refresh
Your single-page app works from the home page, but the host has no file for deeper URLs, so reloads and shared links hit a 404.
Also appears as
- 404: NOT_FOUND Code: NOT_FOUND ID: sfo1::ntg68-1793091406762-e6fdeff1eb27
- Page not found Looks like you’ve followed a broken link or entered a URL that doesn’t exist on this site.
Prompt to fix it
My deployed app works from the home page, but reloading or opening a link like /dashboard directly shows "404: NOT_FOUND" (or Netlify’s "Page not found"). It’s a single-page app with client-side routing. Work out which host we deploy to from the repo and add the right fallback: a vercel.json rewrite to /index.html for Vercel, public/_redirects with "/* /index.html 200" for Netlify, or not_found_handling: "single-page-application" for Cloudflare Workers. Keep real files under /assets served normally, and add a React Router catch-all route for unknown paths. Don’t switch to HashRouter.
Paste into Layerwise or any AI coding tool.
What it means
Apps built with Vite and React Router are single-page apps: the server has one real page, index.html, and JavaScript draws /dashboard or /settings in the browser. Clicking a link works because the router changes the URL without asking the server. A reload or a shared link sends /dashboard straight to the host, which looks for a file by that name, finds none, and returns 404.
The fix is a rewrite: a host rule that answers unknown paths with index.html so the router can take over. Vercel, Netlify, and Cloudflare check for real files first, so your JavaScript, CSS, and images keep loading normally.
It works on your machine because Vite’s dev server and vite preview already fall back to index.html. That’s why the bug only appears after you deploy.
Common causes
- The app deploys to Vercel without a
vercel.jsonrewrite, so only/maps to a file. - A Netlify site has no
_redirectsfile in the published folder, often because it sits in the project root instead ofpublic/. - A custom server or Nginx config serves static files without a fallback to
index.html. - The app is on GitHub Pages, which has no rewrite rules, so deep links get its 404 page.
How to fix it
- On Vercel, add a
vercel.jsonat the project root that rewrites/(.*)to/index.html, then redeploy. - On Netlify, create
public/_redirectswith the line/* /index.html 200. The200makes it a rewrite, so the URL stays the same. - On Cloudflare Workers, set
not_found_handlingto"single-page-application"in theassetssection of your Wrangler config. Cloudflare Pages does this on its own when the build has no top-level404.html. - Add a catch-all route (
path="*") in React Router so unknown URLs show your own not-found page. - Test by opening a deep link like
/dashboardin a new tab on the deployed site.
Example fix
{
"rewrites": [{ "source": "/(.*)", "destination": "/index.html" }]
}Related errors
All errorsFailed to load module script
The browser asked for your app’s JavaScript and got an HTML page back, so it refused to run it and the page stayed blank.
useNavigate() may be used only in the context of a <Router>
A component used React Router’s navigation outside the router, so it had no route information to work with.
Unexpected token '<', "<!DOCTYPE "... is not valid JSON
Your code expected JSON, but the server sent back an HTML page, usually a 404 page or your app’s own index.html.
ERR_TOO_MANY_REDIRECTS
The site keeps redirecting the browser in a circle, usually between HTTP and HTTPS or between two domains, so the browser stops trying.
Build with an agent that checks its work
The Layerwise agent clicks through the live preview and reads the console, so it catches errors before you do.