DEV Community

Cover image for Migrating from react-router to wouter
Aleksei Berezkin
Aleksei Berezkin

Posted on

4 1 1 1

Migrating from react-router to wouter

Artwork: https://code-art.pictures/

Why migrate to wouter?

react-router adds about 30 kB (minified) to your bundle, while wouter requires less than 4 kB. Although the react-router team has made significant efforts in version 7 to optimize its bundle size, it still feels excessive if your primary task is simply switching between a few routes.

Moreover, implementing server-side rendering (SSR) with wouter is straightforward. In contrast, with react-router v7, SSR is only easy when you use it as a framework. If you prefer to use it as a library, the process is unclear since it's not documented — an omission that's both surprising and frustrating, to be honest.

Why stay with react-router?

react-router is a mature library with a large and active community. If your project involves complex routing scenarios, react-router is more likely to provide the tools and support you need.

Hint: If you decide to stick with react-router, be sure to upgrade from v6. Version 7 is about twice as efficient in terms of bundle size.

1. Updating deps to wouter

npm uninstall react-router react-router-dom
npm i wouter
Enter fullscreen mode Exit fullscreen mode

If you're already on react-router v7, you probably don't have react-router-dom.

2. Updating Routes to Switch

  • Update imports
  • Change <Routes> to <Switch>
  • In your routes, move elements from element property to <Route>'s children

Before

import { BrowserRouter, Route, Routes } from 'react-router'

function App() {
  return (
    <Routes>
      <Route path='/' element={<Index/>} />
      ...
    </Routes>
  )
}
Enter fullscreen mode Exit fullscreen mode

After

import { Route, Switch } from 'wouter'

function App() {
  return (
    <Switch>
      <Route path='/'>
        <Index/>
      </Route>
      ...
    </Switch>
  )
}
Enter fullscreen mode Exit fullscreen mode

3. Updating Links

Just update imports. wouter has the same API here

Before

import { Link } from 'react-router'
Enter fullscreen mode Exit fullscreen mode

After

import { Link } from 'wouter'
Enter fullscreen mode Exit fullscreen mode

4. Updating navigation

  • Update imports
  • Change useNavigate() to useLocation()
  • Change navigate() to setLocation()

Before

import { useNavigate } from 'react-router'

function MyComponent() {
  const navigate = useNavigate()

  function navToAbout() {
    navigate('/about')
  }

  // ...
}
Enter fullscreen mode Exit fullscreen mode

After

import { useLocation } from 'wouter'

function MyComponent() {
  const [, setLocation] = useLocation()

  function navToAbout() {
    setLocation('/about')
  }

  // ...
}
Enter fullscreen mode Exit fullscreen mode

5. Implementing SSR

I don’t know how to implement SSR with react-router v7 🙂 That’s why, in this step, we’ll implement it from scratch using wouter — it’s surprisingly simple. All you need to do is wrap your app in a <Router> component:

entry-server.js

import { renderToString } from 'react-dom/server'
import { Router } from 'wouter'

function prerenderApp() {
  return renderToString(
    <Router ssrPath='/'>
      <App />
    </Router>
  )
}
Enter fullscreen mode Exit fullscreen mode

entry-client.js

import { hydrateRoot } from 'react-dom/client'
import { Router } from 'wouter'

hydrateRoot(
  document.getElementById('app-root'),
  <Router>
    <App />
  </Router>
)
Enter fullscreen mode Exit fullscreen mode

We are done!

Now run your favorite bundle analyzer (e.g., webpack-bundle-analyzer or vite-bundle-visualizer) and enjoy the results!

Image of Datadog

The Future of AI, LLMs, and Observability on Google Cloud

Datadog sat down with Google’s Director of AI to discuss the current and future states of AI, ML, and LLMs on Google Cloud. Discover 7 key insights for technical leaders, covering everything from upskilling teams to observability best practices

Learn More

Top comments (0)

Playwright CLI Flags Tutorial

5 Playwright CLI Flags That Will Transform Your Testing Workflow

  • --last-failed: Zero in on just the tests that failed in your previous run
  • --only-changed: Test only the spec files you've modified in git
  • --repeat-each: Run tests multiple times to catch flaky behavior before it reaches production
  • --forbid-only: Prevent accidental test.only commits from breaking your CI pipeline
  • --ui --headed --workers 1: Debug visually with browser windows and sequential test execution

Learn how these powerful command-line options can save you time, strengthen your test suite, and streamline your Playwright testing experience. Practical examples included!

Watch Video 📹️

👋 Kindness is contagious

Engage with a wealth of insights in this thoughtful article, valued within the supportive DEV Community. Coders of every background are welcome to join in and add to our collective wisdom.

A sincere "thank you" often brightens someone’s day. Share your gratitude in the comments below!

On DEV, the act of sharing knowledge eases our journey and fortifies our community ties. Found value in this? A quick thank you to the author can make a significant impact.

Okay