Setting up ReactJS SPA routing/redirects on Cloudflare Pages

Written by Codemzy on March 29th, 2023

I ran into a few issues setting up a ReactJS app on Cloudflare Pages because only part of my website was a SPA (single-page application). Here's how I fixed routing and got my SPA to work.

Single-page applications like ReactJS are pretty popular, and you can get them to work with static sites too. But because the JAMstack is serverless, you'll need to do a few URL rewrites to keep your SPA routes working and avoid the dreaded "404 - Page Not Found" error.

Here's how I set things up on Cloudflare Pages.

If your whole static site is a SPA

If your entire Cloudflare Pages static site is a SPA, you are good to go out of the box. Seriously, you are done - there's no need to go any further!

Here's why...

If you've put a ReactJS app or another SPA on Netlify before, you will probably have done something like this in your _redirects file:

/*  /index.html  200

This is a documented rewrite rule for handling single-page apps in Netlify.

This will effectively serve the index.html instead of giving a 404 no matter what URL the browser requests.

- Netlify History pushstate and single-page apps

But you don't need this rule in Cloudflare Pages.

If your project does not include a top-level 404.html file, Pages assumes that you are deploying a single-page application. This includes frameworks like React, Vue, and Angular.

- Cloudflare Single-page application (SPA) rendering

That's pretty cool if your whole website is a SPA. Nothing to do, just deploy your site as-is. But what if it's not?

The beauty of the rewrite rule in Netlify is that your entire site doesn't need to be a SPA for it to work. And that's not the case for Cloudflare Pages (yet).

If part of your static site is a SPA

Let's imagine you have a website with a bunch of static pages, and a ReactJS app running from app.html.

├── css/ 📁
├── js/ 📁
├── about.html 📄
├── app.html 📄 <--- SPA
├── contact.html 📄
├── index.html 📄
└── pricing.html 📄

If you visit /app and start navigating around your ReactJS application, you might be fooled into thinking everything is working.

🚨 News flash - it isn't.

If you hit refresh in your browser on a client-side route, like /app/dashboard, you'll get a "404 - Page Not Found" error.

So what's happening?

Well when you go to /app, your ReactJS (or other SPA) loads up and takes care of the routing. But when you hit refresh, the static site tries to find /app/dashboard.html- and that doesn't exist as a static page.

You need to pass that URL request back to app.html (your SPA) to handle it.

Remember that rewrite rule we created earlier in _redirects? We need another version of that!

You can create a rewrite proxy so that any routes starting with /app (e.g. /app/dashboard, /app/login, /app/register etc) get shown app.html so that React Router (or your other front-end router of choice) can handle the routing.

/app/*  /app.html  200

And this works... in Netlify.

But we're not talking about Netlify today, we are supposed to be talking about Cloudflare Pages.

And this should work in Cloudflare too. And it will do soon - according to the docs. So if you're reading this blog a few weeks/month in the future, by all means, give it a go!

For a while, Cloudflare Pages _redirects didn’t support proxying. And while it does now (according to the docs), at the time of writing this post - it wasn't working in production yet. At least, not with dynamic routes. So I couldn't handle a partial SPA static site in Cloudflare Pages _redirects.

That doesn't mean you can't get a partial SPA to work in Cloudflare, you absolutely can. And here's how...

SPA routing with transform rules

Until the rewrites start working in Cloudflare Pages (which should be soon), you can use transform rules to handle the rewrite instead.

Cloudflare has some pretty flexible route handling, and URL rewrite is exactly what we need.

Don't worry if you are on the free plan, you get 10 transform rules included, and you are only going to need to use one to get this to work!

Here's what you need to do:

  1. In Cloudflare, head to Rules > Transform Rules

cloudflare transform rules menu

  1. Click Create rule
  2. Create the transform rule

cloudflare transform rules add

☑️ Custom filter expression

Hostname equals And URI Path starts with /app/


☑️ Rewrite to... Static / app

cloudflare transform rules rewrite

This would be if your ReactJS/SPA is at the route /app in your static site. If it's somewhere else, like /user replace app with user in the settings above.

Click Save

Ta-da! Now your SPA works on Cloudflare Pages.