When to Avoid BrowserRouter in React Router
This article explores the specific scenarios where
BrowserRouter is not the ideal choice for your React
application. While it is the standard routing option for modern web
apps, certain environments—such as static hosting services, server-side
rendering, non-browser environments, and micro-frontend
architectures—require alternative routers like HashRouter,
MemoryRouter, or StaticRouter to function
correctly.
1. Hosting on Static File Services (Without Server Configuration)
BrowserRouter relies on the HTML5 History API, which
requires the hosting server to redirect all incoming traffic to
index.html. If a user refreshes the page on a route like
/about, the server searches for a physical
/about/index.html file.
If you are hosting your application on platforms that do not support
easy URL rewriting or wildcard redirection—such as standard GitHub
Pages, Amazon S3 (without CloudFront routing rules), or shared cPanel
hosting—users will encounter 404 errors on page refresh. In these cases,
you should avoid BrowserRouter and use
HashRouter instead, as it uses the URL
hash (#/about) which servers ignore.
2. Server-Side Rendering (SSR)
BrowserRouter depends directly on the browser’s DOM and
the window object to manage history. During server-side
rendering (using Node.js, Express, etc.), the code executes on the
server where the browser environment does not exist, causing the
application to throw undefined errors.
When rendering your React application on the server, you must avoid
BrowserRouter on the server entry point and use
StaticRouter (from
@remix-run/router or react-router-dom/server).
StaticRouter takes a static location prop (the requested
URL) and renders the matching components without relying on browser
APIs.
3. Unit Testing React Components
When writing unit tests for components that contain navigation or
route-dependent logic, using BrowserRouter can make tests
brittle and hard to isolate. Tests typically run in a simulated
environment (like Jest and JSDOM) where manipulating the actual browser
history is unnecessary and difficult.
Instead of BrowserRouter, you should use
MemoryRouter in your test suites.
MemoryRouter stores the routing history entirely in memory,
allowing you to easily initialize tests at specific URLs and assert
navigation changes without interacting with a real browser address
bar.
4. Mobile and Non-Browser Environments
If you are building mobile applications using React Native, or desktop applications using Electron, there is no traditional web browser address bar.
Using BrowserRouter in these environments is either
impossible or highly impractical. For React Native, navigation libraries
like React Navigation are preferred. For Electron apps where URL
manipulation can interfere with file-system loading protocols,
MemoryRouter or
HashRouter is a much safer choice to
manage internal application state.
5. Micro-Frontends and Embedded Widgets
When building embedded widgets or micro-frontend architectures where
multiple React applications coexist on a single page, using
BrowserRouter can cause major conflicts.
If multiple independent applications attempt to manipulate the same
global window.history and address bar simultaneously, they
will overwrite each other’s routing states. To prevent this, embedded
widgets and secondary micro-frontends should use
MemoryRouter to manage their internal
views independently without touching the browser’s URL.