Netlify won’t serve sitemap.xml and robots.txt in Vite + React Router setup (tried __redirects and netlify.toml)

Hey folks, I’ve been stuck trying to get Netlify to correctly serve my sitemap.xml and robots.txt in a Vite + React Router app. The app is built with React and uses client-side routing (react-router-dom). I’m deploying the built dist/ folder directly to Netlify (using drag-and-drop).

:white_check_mark: What I’ve done so far:

  • :white_check_mark: Placed sitemap.xml and robots.txt inside the public/ folder so they end up inside dist/ after vite build
  • :white_check_mark: Verified they exist in dist/ after build
  • :white_check_mark: Created a __redirects file inside dist/ with:bashCopyEdit/sitemap.xml /sitemap.xml 200 /robots.txt /robots.txt 200 /* /index.html 200
  • :white_check_mark: Also tried creating a netlify.toml at the root with:tomlCopyEdit[[redirects]] from = “/sitemap.xml” to = “/sitemap.xml” status = 200 [[redirects]] from = “/robots.txt” to = “/robots.txt” status = 200 [[redirects]] from = “/*” to = “/index.html” status = 200

:police_car_light: The issue:

No matter what I do, Netlify keeps routing /sitemap.xml and /robots.txt through the SPA (React), returning index.html instead of the actual files.

I’ve even opened the deployed dist/ folder and verified that:

  • __redirects is present
  • sitemap.xml and robots.txt are present

Yet, when I access https://my-site.netlify.app/sitemap.xml — I get the React app, not the raw XML.

:thinking: What am I missing?

  • Is there a Netlify cache or something overriding the redirects?
  • Any Vite-specific quirks I’m missing?

If anyone has solved this (or has a working config they could share), I’d really appreciate it :folded_hands:

:light_bulb: Tech stack:

  • Vite
  • React + React Router (SPA)
  • Tailwind
  • Deployed via Netlify Drop (manual upload of dist/)

Thanks in advance!

@riston996 It’s hard to know what is real information in your post, and what might be entirely wrong/fake, since the post appears to have been written by ChatGPT.

So I’m hesitant to spend much time even reading it.

E.g. At a glance I can see you say __redirects several times, but that’s wrong, it would be _redirects

You shouldn’t need redirect/rewrite for a file that exists, e.g. (/sitemap.xml to /sitemap.xml), that’s what Shadowing already accounts for. I would only expect to see the contents of the index.html for paths that didn’t exist as their own files.

Use can use the Deploy File Browser to see what you’ve actually deployed.

You should remove unnecessary rewrites/redirects in your _redirects and netlify.toml to avoid confusion.

1 Like

lol, I spend a long time using different methods to debug it and then asked chatgpt summarise all steps taken but the issue is the same.

Tried your suggestions, removed everything and tried again, but still serving index.html instead of the files.

The deploy file browser shows the file, but when i request for file, reactrouter intercepts it and serves me “index”

@riston996 Excuse my ignorance but when you say “reactrouter” my understanding is that’s “client side routing”, is that correct?

Or are you dealing with something that’s running via serverless/edge functions?

If it’s only a client side router, then it cannot intercept direct requests for the files.

As a ‘static site’, it should be as I’ve outlined.

If you had no rewrites/redirects at all in your _redirects or netlify.toml you would expect:

  1. Requests to / to load (because the /index.html file actually exists)
  2. Navigating to other pages to work (because it’s happening via ajax)
  3. Direct requests to other pages to fail with 404 (as there is no .html for them, and no rewrite)
  4. Direct requests for your /sitemap.xml and /robots.txt to work (provided the files exist)

If you had a single rewrite of:

_redirects

/*  /index.html  200

Then you would expect:

  1. Requests to / to load (because the /index.html file actually exists)
  2. Navigating to other pages to work (because it’s happening via ajax)
  3. Direct requests to other pages to work as they’re being rewritten to /index.html
  4. Direct requests for your /sitemap.xml and /robots.txt to work due to shadowing

I’d only expect the contents of the /index.html to be served if…

A

The file being requested didn’t exist
If it did exist it should be served due to shadowing
If it didn’t exist it’d satisfy the wildcard rewrite and serve the /index.html

or

B

Your rewrite was defined with force
In which case shadowing is ignored and the rewrite to /index.html always occurs

Thanks a lot nathan, its my bad, it is lollapalooza effect. I had installed it as PWA. The “workbox” library which meant precache the data was intercepting the route resulting it serving index.html. after i added exception to the routes it got solved. This should have been a really simple problem but i have made the app unnecessary complicated by also making it a PWA.

But thanks for your feedback fueled the further solving of this problem.

It’s no problem, in future when requesting assistance from fellow humans you should provide a link to the project instead of just a placeholder. It’ll let them test their own assumptions and you’ll get a faster more accurate response.

Great work hunting the issue down.

1 Like