VibeCPR

← All fixes

Deploy · Routing

Fix "404: NOT_FOUND" on refresh in a React/Vite app on Vercel

Updated · Applies to: Vercel, Vite, React Router, Lovable, Bolt, Cursor

TL;DR fix: Vercel looks for a real file at /dashboard and doesn't find one, because your single-page app only has index.html. Add vercel.json at the repository root with {"rewrites":[{"source":"/(.*)","destination":"/index.html"}]}, commit it, and redeploy. Do not add this to Next.js projects.

Steps

  1. Confirm it's an SPA routing issue. The home page loads and in-app navigation works, but refreshing or opening a URL like /dashboard directly shows 404: NOT_FOUND.
  2. Create vercel.json at the repository root. Add a catch-all rewrite to /index.html. If you have serverless functions under /api, exclude them from the rewrite.
  3. Commit the file. Make sure vercel.json is tracked by git and not in .gitignore. Vercel shows no error if the file is missing, so the rewrite just silently doesn't apply.
  4. Check the framework preset. In your Vercel project settings, the Framework Preset should be Vite. Vercel notes that a preset of Other can stop even a correct rewrite from taking effect.
  5. Redeploy and test a deep link. Open https://your-app.vercel.app/some/route directly and refresh it.

The file

vercel.json at the root of your repo:

{
  "rewrites": [
    { "source": "/((?!api/).*)", "destination": "/index.html" }
  ]
}

The (?!api/) part keeps any /api/* serverless functions working. If you don’t have any, "/(.*)" is fine.

Vercel’s guide explains the cause: “Vercel resolves every URL as a server-side filesystem path by default… It is wrong for single-page applications (SPAs) built with Vite, Create React App, or similar tools.”

Prompt for your AI tool

Deep links 404 on Vercel (404: NOT_FOUND) in our Vite + React Router app. Add vercel.json at the repo
root with a catch-all rewrite to /index.html that excludes /api/, make sure it's committed, and confirm
the Vercel framework preset should be Vite. Don't change routing code.

When to get help

Get help if you're on Next.js (where this rewrite is wrong), if API routes start returning HTML after the change, or if you see a blank white page instead of a 404.

FAQ

Why do I get 404: NOT_FOUND on Vercel when I refresh my React app?

Vercel resolves each URL as a file path by default. A Vite or Create React App single-page app only has index.html, and React Router handles routes in the browser, so a direct request to /dashboard has no file to serve. Add a catch-all rewrite to /index.html in vercel.json.

Should I use routes or rewrites in vercel.json?

Use rewrites. Vercel's guidance for SPAs is a catch-all rewrite: { "rewrites": [{ "source": "/(.*)", "destination": "/index.html" }] }.

Does this apply to Netlify or Cloudflare Pages?

The cause is the same. On Netlify add a _redirects file with /* /index.html 200. Cloudflare Pages serves index.html for unknown paths automatically when there is no 404.html in the build output.

Sources

Related fixes