Netlify’s 404 Page
You just deployed your first Create React App to Netlify.
Site is live shows up in the scrolling deployment log. Success 🎉
You happily visit your new site and click around the relative links. Nice, React Router has been putting in the work. Everything looks great.
You enter a path in the address bar that you know is handled with React Router… and get hit with “Page Not Found”. Huh?
Convinced that you must’ve done something wrong, you spin up your app in your local dev environment and try to replicate the bug. But the routing is perfectly fine locally. It even works for the production version:
npm run build and
serve -s build. So what’s the problem here?
As opposed to traditional multi-page applications, SPAs only maintain one HTML file, commonly
index.html. Instead of serving a different HTML file for each path, SPAs depend on client-side routing. With almost 3 million weekly downloads, React Router is a popular client-side routing library.
In the simplest terms, React Router connects a path to a component. When the path is hit, React Router inserts the associated elements into the DOM tree, all without a page refresh.
However, for this process to work, the HTTP GET requests must only ever retrieve data from
index.html — all the React Router logic is handled here. This means the server must direct all requests to
So why does this work locally? This is where Webpack comes in.
Ever wonder what exactly happens when you run
npm start in your CRA?
npm start runs
react-scripts start under the hood (check it out in your
package.json). If we peek into the
react-scripts folder under
/node_modules, we see that CRA uses Webpack to bundle and serve your app.
All of your app’s Webpack “settings” live in
For the dev version of the app, Webpack sets the History API Fallback option as true. In
webpackDevServer.config.js, Webpack is instructed to redirect all requests to paths.
publicUrlOrPath which is the base url, http://localhost:3000/, that serves index.html:
For the prod version which is served when you
npm run build and
serve -s build, we turn to
webpack.config.js. Here, we have the Navigate Fallback option set to
paths.publicUrlOrPath + 'index.html':
Voila! Again, Webpack directs all traffic to
Great, this explains why it’s all good in your local environment but what about on Netlify?
Let’s go back to your production build on your local machine. When you run
npm run build, Webpack bundles and minifies all your organized code into the
build folder in your root directory. The contents of this folder are precisely what Webpack serves as the prod version locally, and what Netlify serves to the internet.
But have you ever tried serving your app with Python’s http.server? It requires an
index.html file so we can run it in your prod
$ cd /build $ python3 -m http.server
Head over to http://localhost:8000/. Enter a path that you specified in React Router or click on a relative link and hit refresh. You should experience deja vu and see this 404 error message:
Another 404 page 😞
This is exactly what happens on Netlify.
Netlify’s servers and Python’s http.server do not handle redirects to
index.html. Even though Netlify serves what Webpack bundled, it doesn’t use Webpack to actually serve the page.
Everything works perfectly if you don’t manually enter an address or refresh the page. This is because you aren’t making a new request for these two actions. You’re not navigating away from
index.html and React Router is doing its thing correctly. However, the moment you refresh or enter a URL, the site breaks.
What can you do about this?
Luckily, you can use Netlify’s Redirect options. To implement this, Netlify requires a file titled
\redirects in the root directory. This one liner is where the magic happens:
/* /index.html 200
This rule specifies that all paths (
/*) redirect to
/index.html without changing the URL in the browser address bar (
You can either
- put this
_redirectsfile with the above line in the
publicfolder of your app. Everything in this folder goes untouched into the root directory of
&& echo ‘/* /index.html 200’ | cat >build/_redirectsto your
package.json. If you check the deployment logs, Netlify runs
npm buildbefore every deploy. This way, Netlify manually creates the
_redirectsfile in the root directory every time.
With the addition of the
_redirects file, we’ve replicated what Webpack does on your local machine.
You’ve just successfully fixed the dreaded 404 Netlify bug! In the process we learned about how React Router works for SPAs, Webpack configurations, and Netlify redirection rules.
Since this is a common problem, I found the fix easily by just Googling. It’s a one-liner after all. However, I couldn’t find a solid explanation for why it worked. Hopefully this post fills in that hole.
Netlify isn’t alone! As we saw above, Python’s http.server is another culprit. This sneaky bug happens with any statically hosted SPA. As an alternative to redirects, hash routing also allows SPA client-side routing. Definitely check it out if you’re interested.
Thanks for reading. Happy hacking!