Quick Answer
“This blog fixes the common issue where React or Vite Single Page Applications (SPAs) return a 404 error upon page reload or direct URL access after deployment to Vercel or Firebase. It explains that since SPAs handle routing on the client side, the server must be configured with rewrites to redirect all requests to index.html, allowing the app to handle the sub-routes correctly.”
Similar Error Patterns
404 Not FoundThe requested URL /dashboard was not found on this server.Cannot GET /helpAre You Seeing This?
- Direct URL access returns 404 Not Found after deployment.
- Page reload in the browser shows a server-side 404 error.
- Navigation works fine when clicking links, but fails on refresh.
- Shared links to internal pages (like /profile) don't work for others.
You just deployed your beautiful Vite or React SPA. You click around the navigation links, and everything works perfectly. But then, you refresh the page at `/dashboard` or share a direct link with a friend, and they see it: `404 Not Found`.
This is one of the most frustrating 'it works on my machine' bugs. Locally, your dev server handles these routes effortlessly. In production, the server is looking for a physical file that doesn't exist. Here is how to fix it in 60 seconds.
Quick Fix for 404 on Refresh
- 1Vercel: Add a vercel.json with rewrites to index.html.
- 2Firebase: Add a rewrites rule in firebase.json.
- 3Netlify: Add a _redirects file with /* /index.html 200.
- 4Next.js: No fix needed if using App Router (it handles this automatically).
Root Causes
SPA Routing vs. Server-Side Lookup
In a Single Page Application (SPA), React Router handles 'navigation' by changing the URL in the browser without actually requesting a new file from the server. However, when you reload, the browser *does* ask the server for `/dashboard`. Since there is no `dashboard.html` file on the server, it returns a 404.
React Router handling
React Router is a client-side library. It only starts working *after* `index.html` has loaded. If the server crashes with a 404 before sending `index.html`, React Router never gets a chance to run.
Step-by-Step Fix Guide
The Firebase Fix
Tell Firebase Hosting to redirect all unknown requests to `index.html` so React Router can take over.
// firebase.json
{
"hosting": {
"public": "dist",
"rewrites": [
{
"source": "**",
"destination": "/index.html"
}
]
}
}The Vercel Fix
Vercel needs a `vercel.json` file in your root directory to handle SPA rewrites correctly for non-Next.js apps.
// vercel.json
{
"rewrites": [
{
"source": "/(.*)",
"destination": "/"
}
]
}Wait... What about Next.js?
If you are using the Next.js App Router, you usually do NOT need this. Next.js is a framework that handles routing on the server-side out of the box. This issue primarily affects Vite, Create React App, and standalone React Router DOM setups.
- If you are seeing 404s in Next.js, it's likely a dynamic route configuration issue, not an SPA rewrite issue.
Still Stuck with 404s?
If you've added the rewrites and it's still not working, your hosting setup might be more complex. I can help you debug your Vite/React deployment pipeline.
Fix My DeploymentRelated Errors
404 on Netlify
Create a file named `_redirects` in your `public` folder with the content: `/* /index.html 200`.
Blank page on refresh
Check if your `base` path in `vite.config.ts` matches your deployment subdirectory.
Prevention Strategy
- Always add a deployment configuration file (vercel.json, firebase.json) before your first push.
- Use a deployment checklist that includes 'Direct URL Access' testing.
- Consider using Next.js if you want full-stack routing handled automatically.
Still Stuck With This Issue?
Send your exact error message or deployment issue. I'll respond with a targeted fix.
Need a Deeper Fix?
Describe your full project issue below and I'll get back to you with a targeted fix.