Next.js: Pages Router vs App Router – What’s the Difference?

Table of Contents

  1. Introduction
  2. What is Next.js Router?
  3. Pages Router in Next.js
  4. App Router in Next.js 13+
  5. Key Differences Between Pages Router and App Router
  6. When to Use Each Router
  7. Migrating from Pages Router to App Router
  8. Conclusion

1. Introduction

Next.js 13 introduced a new routing mechanism called the App Router, designed to give developers more flexibility and improve support for complex applications. Although the App Router provides numerous advantages, the older Pages Router is still widely used and fully supported. Understanding the differences between these two routers and their respective strengths is crucial for building modern React apps with Next.js.

In this module, we will explore both routing systems, highlight the key differences, and guide you on when to use each. We’ll also walk through the migration process for moving from the Pages Router to the App Router.


2. What is Next.js Router?

Next.js is built around a file-based routing system that links the file structure in the pages or app directory directly to application routes. Routing in Next.js can be broken down into:

  1. Pages Router (Traditional): This was the default routing system in Next.js before version 13, using the pages directory.
  2. App Router (Introduced in Next.js 13): A new, more flexible routing system introduced in Next.js 13, leveraging the app directory for better layout handling, improved SSR, and more control over nested routes.

While the Pages Router is still available in Next.js 13, the App Router is now the recommended approach for new Next.js projects.


3. Pages Router in Next.js

The Pages Router follows a file-based routing pattern where every file within the pages directory automatically corresponds to a route.

3.1 File-Based Routing

In the Pages Router, the file structure in the pages directory directly correlates to the routes:

  • pages/index.js corresponds to the / route.
  • pages/about.js corresponds to the /about route.
  • pages/contact.js corresponds to the /contact route.
  • Nested routes, like pages/blog/[slug].js, map to dynamic routes /blog/1, /blog/hello-world, etc.

This simple file-to-route mapping system makes it easy to quickly set up and manage routes.

3.2 Dynamic Routes

Dynamic routing in Next.js is handled by using bracket notation in file names, enabling the creation of URLs that accept dynamic parameters. For instance:

  • pages/blog/[id].js maps to /blog/1, /blog/2, etc., and you can access the dynamic id using useRouter().

You can also use optional catch-all routes using [...param] for more flexibility, like pages/posts/[...slug].js, which can match /posts/first-post or /posts/first-post/second-post.

3.3 API Routes

Next.js supports API routes, allowing you to build server-side logic directly inside the Next.js app. These are defined in the pages/api directory:

  • pages/api/hello.js maps to /api/hello, which can handle HTTP requests like GET, POST, etc.

API routes work well for building backend services like form submissions, handling user authentication, or managing simple CRUD operations.

3.4 Static Site Generation and Server-Side Rendering

In the Pages Router, Next.js provides getStaticProps (for Static Site Generation) and getServerSideProps (for Server-Side Rendering). These methods let you pre-render pages based on data fetching at build time or request time.

For example:

  • getStaticProps is used to fetch data at build time, ideal for static content that doesn’t change frequently.
  • getServerSideProps fetches data at request time, allowing for server-side rendered content that can be updated on each page load.

4. App Router in Next.js 13+

The App Router introduced in Next.js 13+ leverages the app directory and offers a more advanced approach to routing, focusing on nested layouts, server-side rendering flexibility, and component composition.

4.1 Folder-Based Routing

The App Router uses a folder-based structure where each directory inside the app folder represents a route segment. For instance:

  • app/page.js corresponds to the / route.
  • app/about/page.js corresponds to the /about route.

This structure allows for more control over layouts and nested routes. In addition to routing, the App Router supports nested layouts, meaning you can define different layouts for different sections of your app.

4.2 Layouts and Nested Layouts

Layouts in the App Router allow you to encapsulate a consistent structure (e.g., header, footer, sidebar) across pages or groups of pages. Layouts are defined in app/layout.js and can be nested to create complex UI structures:

  • app/layout.js would contain the global layout (e.g., header and footer), shared across all pages.
  • app/dashboard/layout.js would define a layout specifically for the /dashboard section, potentially with different navigation.

Layouts allow for reusability of common UI elements across different routes, promoting maintainability and clean code.

4.3 Server-Side Rendering (SSR) and Client-Side Rendering (CSR)

The App Router offers fine-grained control over server-side rendering (SSR) and client-side rendering (CSR).

  • You can define the rendering behavior for individual pages or components. For example, if a component should only render on the server, you can use the use server directive.
  • The App Router introduces React Suspense for managing data fetching, allowing you to control how content is fetched and displayed, and decide which components should render on the server or the client.

SSR can now be applied at a more granular level, and developers have explicit control over how and when content is rendered, ensuring more optimization.

4.4 Advanced Features: use and async

Next.js 13 introduces new hooks and patterns for handling data fetching and asynchronous tasks. The use hook enables components to declaratively fetch data server-side, making it more intuitive than the older getStaticProps and getServerSideProps methods.

Additionally, components in the App Router support asynchronous rendering with async components, enabling better support for dynamic data fetching in complex apps.


5. Key Differences Between Pages Router and App Router

FeaturePages RouterApp Router (Next.js 13+)
Directory StructureUses pages directory for routingUses app directory for routing
Routing SystemFile-based routingFolder-based routing with layouts
Dynamic RoutesFile-based with bracket notationFolder-based with dynamic routes and layouts
LayoutsNo built-in layout systemNative support for layouts and nested layouts
Data FetchinggetStaticProps, getServerSidePropsSupports use and async hooks for data fetching
SSR and CSRAutomatic SSR and CSRGranular control with server/client-side rendering
API RoutesSupported in pages/apiNot directly supported in app/api
Code Splitting and OptimizationBuilt-in automatic splittingEnhanced support for optimized code-splitting and lazy loading

6. When to Use Each Router

Use Pages Router:

  • If your project is relatively simple or small, and you don’t need complex layouts or nested routing.
  • If you’re migrating from an older Next.js app and prefer to keep the traditional structure.
  • If you’re familiar with the Pages Router and don’t require the additional features offered by the App Router.

Use App Router:

  • If you’re starting a new Next.js project and need support for complex layouts, nested routing, and more control over SSR/CSR.
  • For large applications where modular routing and layout composition are necessary.
  • If your project requires advanced features like React Suspense, data fetching with use, and enhanced code-splitting and optimization.

7. Migrating from Pages Router to App Router

Migrating from the Pages Router to the App Router involves several steps:

  1. Move to the app Directory: Begin by migrating your existing files from the pages directory to the app directory. Each page should be converted into a page.js or page.tsx file within the appropriate folder.
  2. Refactor Layouts: Instead of defining global components (like navigation) in each page, move them into a common app/layout.js file. For sections with different layouts, create nested layout files.
  3. Switch Data Fetching: Replace getStaticProps and getServerSideProps with React’s new data-fetching mechanisms (use and async). Refactor components to use hooks like use for fetching data.
  4. Test Thoroughly: Since the App Router introduces significant changes, test all routes, layouts, and SSR functionality thoroughly to ensure everything is working as expected.

8. Conclusion

The Pages Router is still relevant and appropriate for simpler applications or for developers who prefer a more traditional, file-based routing system. However, for modern, large-scale Next.js projects, the App Router offers more advanced features, enhanced flexibility, and better control over routing, rendering, and layouts.

Whether to stick with the Pages Router or switch to the App Router depends on the specific needs of your application. For new projects or when scalability and flexibility are critical, the App Router is the recommended choice.