The Core Idea: File-System Routing

Next.js revolutionized routing by getting rid of complex configuration files. Instead, you create routes simply by adding files and folders to your project. The structure of your file system directly maps to the URL paths of your application. Next.js offers two ways to do this.

1. The Pages Router (The Classic Approach)

This was the original routing system in Next.js. All your routes are defined inside a special pages directory.

  • Basic Routes: A file in the pages directory becomes a route.
  • pages/index.js → /
  • pages/about.js → /about
  • Nested Routes: A folder structure creates nested routes.
  • pages/blog/first-post.js → /blog/first-post
  • Dynamic Routes: To create a route that can handle variable segments (like a user ID or a blog post slug), you use square brackets [] in the filename.
  • pages/blog/[slug].js → Matches /blog/a-great-post, /blog/another-one, etc. The value of slug is available as a query parameter in your component.

Code Example (pages/blog/[slug].js):

JavaScript


import { useRouter } from 'next/router';

const PostPage = () => {
  const router = useRouter();
  const { slug } = router.query; // Access the dynamic part of the URL

  return <p>Reading post: {slug}</p>;
};

export default PostPage;

2. The App Router (The Modern Approach)

Introduced in Next.js 13, the App Router is built on top of React Server Components and is the recommended approach for new applications. It lives in an app directory.

  • Routes are Folders: Instead of files, folders now define the route segments.
  • The page.js file: The UI for a specific route is defined in a special file named page.js inside its corresponding folder.
  • app/about/page.js → /about
  • Layouts: The App Router introduces a powerful concept of layouts. A layout.js file defines a UI that is shared across multiple pages in a segment.
  • app/dashboard/layout.js → A shared sidebar for all dashboard pages.
  • app/dashboard/settings/page.js → The settings page, which appears inside the dashboard layout.
  • Dynamic Segments: Folders use square brackets [] to create dynamic routes.
  • app/blog/[slug]/page.js → Matches /blog/a-great-post, etc. The slug is passed as a prop.

Code Example (app/blog/[slug]/page.js):

JavaScript


// The params object is passed directly as a prop to the page component
function PostPage({ params }) {
  const { slug } = params; // Access the dynamic part of the URL

  return <h1>Reading post: {slug}</h1>;
}

export default PostPage;

Linking Between Pages

Regardless of which router you use, you should always use the <Link> component from next/link for client-side navigation. This prevents a full page reload and provides a much faster, app-like experience.

JavaScript


import Link from 'next/link';

function Navbar() {
  return (
    <nav>
      <Link href="/">Home</Link>
      <Link href="/about">About Us</Link>
      <Link href="/blog/my-first-post">Blog</Link>
    </nav>
  );
}