Why does my React or Vue app deployed on S3 slap me with a 404 on refresh or direct URL visit?
You’ve finally finished your web app and can’t wait to reveal it to the world. The weather is nice, you deploy your code, and the pipeline…
Why does my React or Vue app deployed on S3 slap me with a 404 on refresh or direct URL visit?

404 Not Found: No such key
You’ve finally finished your web app and can’t wait to reveal it to the world. The weather is nice, you deploy your code, and the pipeline is running smoothly as you’re enjoying your 3rd cup of coffee of the day. No more staring at the monotonous localhost.
The web app that you’ve hosted on S3 opens as expected. Until you refresh the page or type the URL manually and come across 404 Not Found.

The error message
However, the root directory loads as expected... How can that be? Did you not configure the routing properly? But it’s running fine on localhost?
A very hmm moment
In simple terms, S3 treats your bucket like a file server.
/dashboard → S3 looks for a file called dashboard. Since the file doesn’t exist in the bucket, it returns 404. The root directory is a little different; S3 serves index.html when you access example.com because you’ve configured it as the Index Document in Static Website Hosting.
This is where single page apps behave differently from regular websites. When you click a link inside a SPA, it never makes a real request to the server. JavaScript handles the navigation entirely.

JavaScript out here doing all the work
Let’s take this a bit further, clicking a link within the app works perfectly fine. But the moment you refresh the page or type in the URL manually, S3 gets involved again and has no idea what /about is. Thus, leading to 404 Not Found, Code: NoSuchKey again.
Why does that happen?
Regular websites use server side routing. Every attempt to navigate to a different page makes a real request to the server and the server responds with a whole new HTML page.
SPA handles navigation differently by swapping out content in the DOM. Thus, not making a full page request.
How does the URL change without a real request?
The single page app utilizes History API that has a method window.history.pushState() to change the URL bar without triggering a real browser navigation. JavaScript is responsible for updating the URL and swapping the content.
The fix
For History API to survive a refresh, the server needs to be configured with a fallback rule.
- Open your website’s S3 bucket in the AWS console.
- Click the Properties tab.
- Scroll down to Static website hosting and click Edit.
- Add “index.html” as the Error document.

S3 Static Website Hosting settings — Note the Error document field
Save the changes and voila! You will no longer see 404 Not Found . From there, your SPA’s JavaScript router reads the URL and renders the correct page.
References
메타데이터
- post_id
- 171d54f8d951
- slug
- why-does-my-react-or-vue-app-deployed-on-s3-slap-me-with-a-404-on-refresh-or-direct-url-visit-171d54f8d951
- url
- https://medium.com/@tahmidrahman_6876/why-does-my-react-or-vue-app-deployed-on-s3-slap-me-with-a-404-on-refresh-or-direct-url-visit-171d54f8d951
- canonical_url
- https://medium.com/@tahmidrahman_6876/why-does-my-react-or-vue-app-deployed-on-s3-slap-me-with-a-404-on-refresh-or-direct-url-visit-171d54f8d951
- author_url
- https://medium.com/@tahmidrahman_6876
- status
- ok
- fetched_at
- 2026-08-20 12:55:18