Not found errors

404 when you refresh a page or open a link to it

The home page works and clicking around works, but refreshing a page like /about, or opening a link to it, gives a 404.

Checked 16 October 2026

The short answer

Your app routes in the browser, so /about has no file of its own on the server. Tell the host to serve index.html for paths it can't find, and the app takes it from there.

Find your cause

4 causes, most likely first

  1. 1

    There's no fallback to index.html

    How to tell: It's a single-page app (React Router, Vue Router, Angular) and only deep links and refreshes fail.

    Fix

    Add the fallback for your host, below.

  2. 2

    The fallback file isn't in the deployed site

    How to tell: You added _redirects or vercel.json, but nothing changed.

    Fix

    netlify.toml and vercel.json belong at the root of the repository; a _redirects file has to end up in the publish folder, so put it in public/. Commit them: a file that's ignored by git never reaches the host.

  3. 3

    A top-level 404.html on Cloudflare Pages

    How to tell: Your build output has a 404.html at the top.

    Fix

    Cloudflare Pages only falls back to your app when there's no top-level 404.html. Remove it from the build output.

  4. 4

    Or avoid the problem altogether

    How to tell: You'd rather not depend on a host setting.

    Fix

    A hash router (/#/about) never asks the server for /about, so it works anywhere. Building each page to its own HTML file (Astro, a Next.js export, SvelteKit with prerendering) works anywhere too, and suits search engines best.

Per host

The fallback for your host

99helpers

Copy index.html to 404.html in your build folder before you drop it (cp dist/index.html dist/404.html). 99helpers serves 404.html for any path without a file, so the app opens and routes from there.

GitHub Pages

Copy index.html to 404.html as a step in the workflow, after the build. GitHub Pages serves 404.html for unknown paths, so the app opens (with a 404 status).

.github/workflows/deploy.yml (a step after Build)
- name: Open the app for any path
  run: cp dist/index.html dist/404.html

Netlify

Add a redirect rule with status 200, which serves index.html without changing the address. Or put a _redirects file with the line /* /index.html 200 in your public/ folder.

netlify.toml
[[redirects]]
  from = "/*"
  to = "/index.html"
  status = 200

Vercel

Add a rewrite in vercel.json at the root of the repository, and commit it.

vercel.json
{
  "rewrites": [{ "source": "/(.*)", "destination": "/index.html" }]
}

Cloudflare Pages

Nothing to add: without a top-level 404.html, Cloudflare Pages serves your home page for any unknown path. If your build makes a 404.html, leave it out.

Questions

Also asked

Is the 404.html trick bad for search engines?

On GitHub Pages the page opens, but with a 404 status, so search engines may leave those addresses out. If search matters, build each page to its own file, or use a host with real rewrites.

Why does it work with npm run dev?

The dev server already sends every unknown path to index.html. Static hosts don't, until you tell them to.

Rather skip build settings altogether?

Build on your computer, where it already works, and drop the folder on 99helpers. The site gets its own address, so there's no base path, workflow or build log to get wrong, and it's online in seconds.

Or skip the setup

Drop it in. It's online in seconds.

A file, a folder or a whole site: 99helpers puts it online at its own address, with no git, no build settings and no DNS to start with. Add your own domain whenever you're ready.