If you are using React Router in a React app, you might encounter an HTTP 404 - Not Found error when you refresh or reload a non root (/) URL.

Screenshot of a 404 error thrown by Amazon AWS S3
404 Not Found error on AWS S3

Why does this happen?

By default, web servers and object storage providers serve files from the disk. So when you go to the root / URL, it will try to serve index.html and if you go to /about-us it will serve /about-us/index.html.

We usually build single-page applications or SPAs with React. SPAs use Javascript to show different content within a single web page. So when you create a production build of a React app, it only generates a single index.html file with references to the Javascript and CSS files necessary to run the React app. Even when we declare several Routes with React Router, only a single index.html file is generated since it uses Javascript to show different Routes within a single page.

So the 404 error occurs because the web server is trying to load different web pages and React SPAs only consist of a single index.html web page.

How to fix it

To fix this problem, we need to configure our web server or object storage to serve index.html for every single path used by React Router. Then when an app is loaded, React Router will read the path and show the Route that is supposed to be displayed at that path.

The easiest way to do this is to configure the web server to serve index.html whenever it receives a URL that refers to a non-existent file. This way, the web server would be able to serve the CSS, JS and other files referenced from index.html correctly since they exist on the disk and return index.html for all the React Router paths which don't have any files.

Nginx and other web servers

This technique of returning different content for URLs is called URL rewriting and if you use Nginx, you can find how to setup it up to work with React Router in this post.

Netlify

You can use Netlify's rewrite feature to serve index.html for all React router paths. This post will walk you through how you can set it up.

AWS S3 and object storage providers

If you are using AWS S3 or an object storage provider like Linode, you can achieve the same result by setting the error page to index.html. This way, the object storage will show index.html whenever a nonexistent file is requested which would start React and allow React Router to show the Route at that path.

For AWS S3, you can set the error page using the AWS Management Console. Go to your S3 Bucket, "Properties" and click "Edit" in the "Static website hosting" section at the bottom. Next, enter index.html as the "Error document" and click "Save changes" at the bottom.

Screenshot of AWS Management Console - S3 bucket properties
S3 bucket properties

Screenshot of AWS Management Console - S3 static website hosting settings
Edit static website hosting options

Screenshot of AWS Management Console - S3 static website hosting settings
Set error document to index.html

If you are using Linode or another S3-compatible object storage provider, you can use s3cmd to set the error page with the following command. Replacewith the name of your bucket.

$ s3cmd ws-create --ws-index=index.html --ws-error=index.html s3://<bucket-name>

AWS CloudFront

If you are using AWS CloudFront, the Error page can be configured under the Error Pages tab in the CloudFront section of the AWS Management Console. Note that you should setup error pages for both 403 and 404 error codes.

Screenshot of AWS Management Console - S3 CloudFront error pages
Setting error pages for a CloudFront distribution

Prabashwara Seneviratne (bash)

Written by

Prabashwara Seneviratne (bash)

Lead frontend developer