Home/Blog/Web Development/Understanding routing in Next.js with the App Router
Home/Blog/Web Development/Understanding routing in Next.js with the App Router

Understanding routing in Next.js with the App Router

Farrukh Rasool
Nov 05, 2024
6 min read

Key Takeaways:

  • Understand how the file and folder structure in the app directory defines routes in Next.js.

  • Learn how to create complex and dynamic routes using dynamic segments like user IDs and product slugs, enhancing the flexibility of your application.

  • Explore how to use layouts and templates to maintain a consistent look across your application for seamless navigation.

  • Learn how to navigate between routes efficiently using the <Link> component and programmatic navigation with the useRouter hook.

  • Enhance navigation speed and user experience by prefetching routes and using the redirect function to handle server-side routing logic.

Next.js is a React framework that allows developers to easily create high-performance, scalable, and SEO-friendly web applications. Among the many advanced features that set it apart from other frameworks, routing plays a key role in enhancing the user experience. In this blog, we'll explore routing in Next.js with the App Router. We’ll break down the key routing concepts in Next.js—such as dynamic routing, nested routes, layouts and templates.

Next.js
Next.js

Suppose that you’re building an online learning platform like Educative, with multiple courses, lesson pages, and project landing pages. Each section of your platform needs to be accessible, guiding learners seamlessly through the content. Without an efficient routing system, users might get lost and miss out on valuable content—just like trying to find a specific chapter in a book with no table of contents. Routing, therefore, serves as a map that helps users navigate through the web application effortlessly.

Next.js - The ultimate way to build React apps

Cover
Next.js - The ultimate way to build React apps

React is an amazing framework that allows you to build front-ends that are unmatched in speed, functionality, and ease of use. Where React falls short though is its ability to optimize for search engines. That’s where Next.js comes in. In this course, you will learn to build a giphy search app using the giphy.com API. To kick things off, you’ll learn how to statically optimize a Next.js page, creating an ultra fast loading experience for users. You’ll then dive into the inner workings of creating your giphy search app. In the back half of the course, you will learn how to optimize for SEO, and how to deploy your application. By the end, you will have a great new framework to add to your resume and a new shiny application to add to your portfolio.

5hrs
Intermediate
12 Playgrounds
6 Quizzes

In traditional React applications, routing is typically managed through external libraries like React Router. Next.js initially simplified this with the Pages Router, where routes were defined using files in the pages directory, each file corresponding to a unique URL path. This approach made routing straightforward but had limitations in managing complex layouts and nested routes.

Want to build something interactive using the Pages Router? Try this project: Build an Interactive E-Library Using Next.js and Tailwind.

Next.js further simplified this file-based routing system with the new App Router, built on React Server Components, that automatically maps your project’s folder structure to URL paths. This new file-based approach makes routing both intuitive and flexible. With the introduction of the app directory in Next.js 13, routing in Next.js has taken a leap forward, offering developers even more flexibility and power. This approach is more modular and allows for features like nested layouts, server components, and streaming.

Pages Router vs App Router
Pages Router vs App Router

Defining routes#

The App Router works in a new directory named app. In the app directory, the structure of your folders and files defines the routes of your application. Each folder represents a route segment, and the page.js (or page.tsx for TypeScript) file within a folder represents a page for that route.

Look at the example below for reference:

app/
├── page.js # Renders at / route
├── about/
│ └── page.js # Renders at /about route
└── contact/
│ └── page.js # Renders at /contact route
├── dashboard/
│ └── page.js # Renders at /dashboard route
File structure

Nested routing#

Nested routing allows you to create complex, hierarchical routes that mirror the structure of your application. Nested routes are simply a matter of nesting folders within each other.

For example, a dashboard with multiple sub-pages (like settings or analytics) would be structured as follows:

app/
├── dashboard/
│ ├── page.js # Renders at /dashboard
│ └── settings/
│ └── page.js # Renders at /dashboard/settings
└── analytics/
└── page.js # Renders at /dashboard/analytics
Nested routes

This structure not only keeps your project organized but also clearly explains how different parts of your application relate to one another.

To get a hands-on experience on Next.js routing refer to the Build a Music Sharing App with Next.js and the MERN Stack project.

Dynamic routes#

Dynamic routing is a powerful feature in Next.js, enabling the creation of pages using Dynamic Segments that are based on dynamic data such as user IDs, product slugs, or any other variable path segment. Check out this project: Next.js Internationalization: Building a Multilingual Blog App to see dynamic routing in action.

Dynamic routes are defined by placing folder names in square brackets, e.g., [id] or [postId]. This allows Next.js to treat part of the URL as a variable. Consider the example below:

app/
├── user/
│ └── [id]/
│ └── page.js # Renders at /user/:id
Structure of a dynamic route

In the above example, id is the Dynamic Segment for users that you can access within your Page component. Look at an example of how to use dynamic routes:

The following code will render a page based on the URL, such as /user/9.

export default function User({ params }) {
return <h1>User Id: {params.id}</h1>;
}
Usage of dynamic route

Layouts and templates#

Consistency in UI across different pages is crucial for a seamless user experience. Next.js facilitates this through layouts and templates, allowing you to share common UI elements like headers, footers, or sidebars across multiple routes. Next.js provides us with special files layout.js and template.js for this.

Layouts#

A layout in Next.js is a special component that wraps the pages and preserves the state between navigations, avoiding unnecessary re-renders and is shared between multiple routes.

A layout can be defined by exporting a React component as default from a file, e.g., layout.js. This component accepts a prop, children, which is populated with the child layout or the page when it is rendered.

Here is an example of a layout:

// app/dashboard/layout.js
export default function LayoutDashboard({ children }) {
return (
<div>
<Header /> {/* The shared UI — header */}
<main>{children}</main>
</div>
);
}
Dashboard layout

This layout will wrap all the pages within the dashboard route, ensuring that the header persists as users navigate. In the following example, the defined layout is shared with the /dashboard and /dashboard/analytics pages:

app/
├── dashboard/
│ └── layout.js
│ └── page.js # Renders at /dashboard
│ └── analytics/
│ └── page.js # Renders at /dashboard/analytics

The root layout is required and must include the <html> and <body> tags, allowing us to define the global structure of the HTML document. It is defined at the top level of the app directory and applies to all routes.

export default function LayoutRoot({ children }) {
return (
<html>
<body>
<main>{children}</main>
</body>
</html>
);
}
Root layout

Templates#

Like layouts, templates also wrap up a child layout/page. Contrary to layouts, templates create a new instance for each of the children on navigation. This basically means that a new instance of the child is mounted, DOM elements are recreated, and the state is not preserved when a user navigates between routes that share a template.

Explore more interactive projects on Educative to get a hands-on experience.

A template can be defined by exporting a React component as default from a file, e.g., template.js. This component accepts a prop, children, which is populated with the child layout or the page when it is rendered.

Consider the example below:

// app/template.jsLayout
export default function AppTemplate({ children }) {
return <div>{children}</div>
}
Defining a template

Linking and navigating#

Linking and navigation in Next.js is about efficiently and smoothly moving between pages. Let’s look at some of the ways to navigate between routes in Next.js:

Using the <Link> component#

The <Link> component provides client-side navigation between routes. It enhances the basic HTML <a> tag with additional features like prefetching. It is the primary and recommended way to navigate between routes in Next.js. We can use it by importing it from next/link, and passing a href prop to the component:

import Link from 'next/link';
export default function HomePage() {
return <Link href="/settings">Go to Settings</Link>;
}
<Link> component

By default, Next.js will prefetch the linked page, improving load times when the user clicks the link.

Using the useRouter hook in Client Components#

For scenarios where you need to navigate programmatically from Client Components, Next.js provides the useRouter hook. We can use it by importing it from next/navigation, and using the push method to navigate to the route:

import { useRouter } from 'next/navigation';
export default function HomePage() {
const router = useRouter();
return (
<button onClick={() => router.push('/settings')}>Go to Settings</button>
);
}
The useRouter hook

Using the redirect function in Server Components#

For Server Components, we use the redirect function to programmatically change routes.

import { redirect } from 'next/navigation'
async function fetchUserProducts(id) {
const res = await fetch('https://educative.io/api/user_products')
if (res.status !== 200) return undefined
return res.json()
}
export default async function HomePage({ id }) {
const userProducts = await fetchUserProducts(id)
if (!userProducts) {
redirect('/login')
}
// Rest of the component
}
The redirect function

Mastering Next.js goes beyond just building basic applications; it’s about fully understanding its advanced features like Incremental Static Regeneration (ISR), dynamic routing, and data fetching strategies. By leveraging these advanced tools, you can create scalable, high-performance, and SEO-friendly web applications tailored to your needs.

To get hands-on experience, dive into some Next.js projects. The best way to solidify your understanding is by building and experimenting with real-world applications.

Continue learning Next.js#

Explore these projects for hands-on practice:

Explore these courses for in-depth knowledge on Next.js routing:

Frequently Asked Questions

How does file-based routing work in Pages Router in Next.js?

File-based routing in Next.js maps your project’s folder structure to URL paths. Each folder represents a route segment, and each file represents a page. For example, a file named about.js in the pages directory would correspond to the /about route.

What is the difference between the Pages Router and the App Router in Next.js?

How do I set up dynamic routes in Next.js?

What are layouts and templates, and how do they differ?

What’s the difference between <Link> and useRouter?

How does the new App Router in Next.js 13 improve routing?


  

Free Resources