Routing

React Router / Next.js

Our pick

Next.js

For new projects, it has more than page switching: it's built to rank well in search and comes with ways to publish your site. This site is built with Next.js too

Compare the result

We built the same thing with each library. Try them out.

React Router

Compare the code

Edit the code and the preview on the right updates.

import { MemoryRouter, Routes, Route, Link, useParams, useLocation } from "react-router"

const items = [
  { slug: "apple", name: "Apple", price: 1.5 },
  { slug: "orange", name: "Orange", price: 1 },
]

// Styles (not the point of this demo)
const linkStyle = { color: "#18181b", textDecoration: "none", fontSize: 14 }

function Home() {
  return <h2 style={{ margin: 0, fontSize: 18 }}>Home</h2>
}

function ItemList() {
  return (
    <div>
      <h2 style={{ margin: "0 0 8px", fontSize: 18 }}>Products</h2>
      <ul style={{ listStyle: "none", margin: 0, padding: 0 }}>
        {items.map((item) => (
          <li key={item.slug} style={{ padding: "8px 0", borderTop: "1px solid #f4f4f5" }}>
            <Link to={"/items/" + item.slug} style={linkStyle}>
              {item.name} →
            </Link>
          </li>
        ))}
      </ul>
    </div>
  )
}

function ItemDetail() {
  // Take the :slug part of the URL (e.g. apple)
  const { slug } = useParams()
  const item = items.find((i) => i.slug === slug)

  if (!item) {
    return <p>Product not found</p>
  }

  return (
    <div>
      <h2 style={{ margin: 0, fontSize: 18 }}>{item.name}</h2>
      <p style={{ margin: "4px 0 12px", color: "#71717a" }}>${item.price.toFixed(2)}</p>
      <Link to="/items" style={linkStyle}>← Back to the list</Link>
    </div>
  )
}

// Show the current URL (the demo has no address bar)
function CurrentUrl() {
  const location = useLocation()
  return (
    <span style={{ marginLeft: "auto", padding: "2px 8px", borderRadius: 6, background: "#f4f4f5", color: "#71717a", fontSize: 12, fontFamily: "monospace" }}>
      {location.pathname}
    </span>
  )
}

export default function App() {
  return (
    // MemoryRouter: switches URLs inside the demo only (a normal site uses BrowserRouter)
    <MemoryRouter>
      <div style={{ maxWidth: 360, margin: "0 auto", border: "1px solid #e4e4e7", borderRadius: 12, fontFamily: "system-ui, sans-serif", overflow: "hidden" }}>
        <nav style={{ display: "flex", alignItems: "center", gap: 16, padding: "10px 16px", borderBottom: "1px solid #f4f4f5" }}>
          <Link to="/" style={linkStyle}>Home</Link>
          <Link to="/items" style={linkStyle}>Products</Link>
          <CurrentUrl />
        </nav>

        <div style={{ padding: 16 }}>
          {/* The table of URLs and screens (path = the URL, element = the screen to show) */}
          <Routes>
            {/* At "/", show Home */}
            <Route path="/" element={<Home />} />
            {/* At "/items", show the product list */}
            <Route path="/items" element={<ItemList />} />
            {/* At "/items/anything", show the product details (:slug = anything can go here) */}
            <Route path="/items/:slug" element={<ItemDetail />} />
          </Routes>
        </div>
      </div>
    </MemoryRouter>
  )
}

Building the same thing with Next.js

app/page.tsx → /

export default function Page() {
  return <h2>Home</h2>
}

app/items/page.tsx → /items

import Link from "next/link"
import { items } from "@/data/items"

export default function Page() {
  return (
    <div>
      <h2>Products</h2>
      <ul>
        {items.map((item) => (
          <li key={item.slug}>
            <Link href={"/items/" + item.slug}>{item.name}</Link>
          </li>
        ))}
      </ul>
    </div>
  )
}

app/items/[slug]/page.tsx → /items/apple, etc.

import Link from "next/link"
import { notFound } from "next/navigation"
import { items } from "@/data/items"

export default async function Page({
  params,
}: {
  params: Promise<{ slug: string }>
}) {
  // Take the [slug] part of the URL (e.g. apple)
  const { slug } = await params
  const item = items.find((i) => i.slug === slug)

  if (!item) {
    notFound()
  }

  return (
    <div>
      <h2>{item.name}</h2>
      <p>${item.price.toFixed(2)}</p>
      <Link href="/items">← Back to the list</Link>
    </div>
  )
}

Comparison

As of October 2026

React Router

Official site ↗

Features

A library that adds page switching to a React app. You write a table in code that says "this URL shows this screen". Pages are built in the browser

Best for

Adding pages to an existing React app. Apps that don't need to show up in search, like admin screens behind a login

Next.js

Our pickOfficial site ↗

Features

A framework for building sites with React. Your folder and file structure becomes the URL (app/basics/page.tsx → /basics). Pages are built on the server before being sent

Best for

Building a new site you want to show up in search: blogs, shops, product pages, and so on