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.